home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / mac / macmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  67.1 KB  |  2,409 lines  |  [TEXT/R*ch]

  1. /* Map graphics for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995, 1996 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. extern void location_desc PARAMS ((char *buf, Side *side, Unit *unit, int u, int x, int y));
  11. extern int supply_desc PARAMS ((char *buf, Unit *unit, int mrow));
  12. #include "macconq.h"
  13. extern int gamewinw;
  14. extern int topunithgt;
  15. extern void draw_unit_info(Map *map);
  16. extern void draw_unit_blast(Map *map, Unit *unit, int blast);
  17. extern void clear_unit_blast(Map *map, Unit *unit, int blast);
  18.  
  19. static void draw_borders(Map *map, int x, int y, int b);
  20. static void draw_connections(Map *map, int x, int y, int c);
  21. static void draw_units(Map *map, int x, int y);
  22. static void draw_unit_and_occs(Map *map, Unit *unit, int sx, int sy, int sw, int sh);
  23. static void draw_people_row(Map *map, int x0, int y0, int len);
  24. static void draw_materials(Map *map, int x, int y);
  25. static void draw_ai_region(Map *map, int x, int y);
  26. static void draw_info_text(Map *map, int x, int y, int len, char *buf);
  27.  
  28. /* For these accessors, x must already be wrapped. */
  29.  
  30. #define cell_overlay(x, y)  \
  31.   (tmpdrawlighting  \
  32.    ? (night_at(x, y) ? -2 : (tmpdrawcoverage ? (cover(dside, x, y) == 0 ? -1 : 0) : 0))  \
  33.    : (tmpdrawcoverage ? (cover(dside, x, y) == 0 ? -1 : 0) : 0))
  34.  
  35. #define cell_terrain(x, y, power)  \
  36.   (dside->see_all ? terrain_at(x, y)  \
  37.    : (terrain_visible(dside, x, y) ? vterrain(terrain_view(dside, x, y)) : NONTTYPE))
  38.  
  39. #define cell_style(x, y, power)  \
  40.   ((terrain_visible(dside, x, y) || unseen_image != NULL) ? (power >= 4 ? usepolygons : useblocks) : dontdraw);
  41.  
  42. #define SHIFT_ORIGIN(m) {  \
  43.   (m)->osx = (m)->vp->sx - (m)->conw;  (m)->osy = (m)->vp->sy - (m)->toph;  \
  44.   SetOrigin((m)->osx, (m)->osy);  \
  45.   }
  46.  
  47. #define RESET_ORIGIN(m) {  \
  48.   (m)->osx = 0;  (m)->osy = 0;  \
  49.   SetOrigin((m)->osx, (m)->osy);  \
  50.   }
  51.  
  52. static void draw_cliffs(Map *map, int x, int y);
  53. static void draw_contours(Map *map, int x, int y);
  54.  
  55. int tmpdrawlighting;
  56.  
  57. int tmpdrawcoverage;
  58.  
  59. /* The width of the left-side control panel. */
  60.  
  61. int conwid = 32;
  62.  
  63. /* The height of the top line. */
  64.  
  65. int tophgt = 16;
  66.  
  67. int mapnum = 1;
  68.  
  69. int nummaps = 0;
  70.  
  71. int lastmaph = -1, lastmapv = -1;
  72.  
  73. /* Handles of the pictures that display all the map control buttons. */
  74.  
  75. PicHandle tlcontrols = nil;
  76. PicHandle blcontrols = nil;
  77.  
  78. char *mouseover = "something";
  79.  
  80. int animation_pattern_state;
  81.  
  82. /* This tests whether the given cell might possibly be visible on the given map.
  83.    Not as precise as a real cliprect calculation. */
  84.  
  85. int
  86. at_all_visible(Map *map, int x, int y)
  87. {
  88.     return cell_is_visible(map->vp, x, y);
  89. }
  90.  
  91. /* Decide whether given location is away from the edge of the map's window. */
  92.  
  93. int
  94. in_middle(Map *map, int x, int y)
  95. {
  96.     return cell_is_in_middle(map->vp, x, y);
  97. }
  98.  
  99. /* Draw an individual detailed cell, as a row of one, on all maps. */
  100.  
  101. void  
  102. update_cell_display(Side *side, int x, int y, int rightnow)
  103. {
  104.     int i;
  105.     Unit *unit;
  106.     GrafPtr oldport;
  107.     Map *map;
  108.     RgnHandle tmprgn;
  109.     
  110.     if (active_display(side)) {
  111.         GetPort(&oldport);
  112.         for_all_maps(map) {
  113.             /* If update was only to report changes in undrawn info, maybe don't bother. */
  114.             if ((rightnow == 34 && !map->drawtemperature) 
  115.                 || (rightnow == 35 && !map->drawwinds)
  116.                 || (rightnow == 36 && !map->drawcover)
  117.                 )
  118.               continue;
  119.             if (at_all_visible(map, x, y)) {
  120.                 /* Set up the drawing context. */
  121.                 SetPort(map->window);
  122.                 tmprgn = NewRgn();
  123.                 GetClip(tmprgn);
  124.                 /* Clip to the content area of the map's window. */
  125.                 ClipRect(&(map->contentrect));
  126.                 SHIFT_ORIGIN(map);
  127.                 /* Draw the cell. */
  128.                 draw_row(map, x, y, 1, TRUE);
  129.                 /* Draw any selections that are here. */
  130. #if 1 /* (should eventually go away, when basic drawing does this right) */                
  131.                 for (i = 0; i < map->numselections; ++i) {
  132.                     unit = map->selections[i];
  133.                     if (unit && unit->x == x && unit->y == y) {
  134.                         draw_selected_unit(map, unit);
  135.                     }
  136.                 }
  137. #endif
  138.                 RESET_ORIGIN(map);
  139.                 SetClip(tmprgn);
  140.                 DisposeRgn(tmprgn);
  141.                 if (map->numselections > 0) {
  142.                     unit = map->selections[0];
  143.                     if (in_play(unit) && unit->x == x && unit->y == y) {
  144.                         draw_unit_info(map);
  145.                     }
  146.                 }
  147.             }
  148.         }
  149.         SetPort(oldport);
  150.     }
  151. }
  152.  
  153. /* Create a new map window and all its paraphernalia. */
  154.  
  155. Map *
  156. create_map(int power)
  157. {
  158.     int m, t, i, x, y, mainwidth, mainheight;
  159.     Rect vscrollrect, hscrollrect;
  160.     Map *map;
  161.     WindowPtr win;
  162.  
  163.     build_optional_terrain_type_menu();
  164.     DGprintf("Creating map, mag power %d\n", power);
  165.     map = (Map *) xmalloc(sizeof(Map));
  166.     map->vp = new_vp();
  167.     calc_vision(dside);
  168.     set_map_power(map, power);
  169.     /* Pick an appropriate focus of the view. */
  170.     pick_a_focus(dside, &x, &y);
  171.     set_view_focus(map->vp, x, y);
  172.     /* Set default values for the display controls. */
  173.     map->conw = conwid;
  174.     map->toplineh = tophgt;
  175.     map->topunith = topunithgt;
  176.     map->toph = map->toplineh + map->topunith;
  177.     map->drawterrain = TRUE;
  178.     /* Display all types of borders and connections normally. */
  179.     /* (auxterraintypes[t] == 0 implies not optional type - i can't overflow
  180.        drawauxterrain because at least one ttype must be cell terrain.) */
  181.     /* (Addressing of map->auxterraintypes is 1-based instead of 0-based
  182.         because it corresponds to menu items.) */
  183.     i = 1;
  184.     for_all_terrain_types(t) {
  185.         if (!t_is_cell(t)) {
  186.             map->auxterraintypes[i++] = t;
  187.             map->drawauxterrain[t] = TRUE;
  188.         }
  189.     }
  190.     map->drawcellpats = TRUE;  /* should get from prefs */
  191.     map->drawunits = TRUE;
  192.     map->drawnames = default_draw_names;
  193.     map->drawpeople = FALSE;
  194.     map->drawelevations = FALSE;
  195.     for_all_material_types(m) {
  196.         map->drawmaterials[m] = FALSE;
  197.     }
  198.     map->nummaterialstodraw = 0;
  199.     map->drawlighting = TRUE;
  200.     map->drawtemperature = FALSE;
  201.     map->drawwinds = FALSE;
  202.     map->drawclouds = FALSE;
  203.     map->drawstorms = TRUE;
  204.     map->drawgrid = default_draw_grid;
  205.     /* Display AI info by default if there is an AI present. */
  206.     map->drawai = side_has_ai(dside);
  207.     /* Don't indicate other maps by default - too confusing initially. */
  208.     map->drawothermaps = FALSE;
  209.     map->autoselect = defaultautoselect;
  210.     map->moveonclick = defaultmoveonclick;
  211.     map->numselections = 0;
  212.     map->maxselections = max(100, numunits + numunits / 2);
  213.     map->selections = (Unit **) xmalloc(map->maxselections * sizeof(Unit *));
  214.     /* Newest map goes on the front of the list. */
  215.     map->next = maplist;
  216.     maplist = map;
  217.     if (hasColorQD) {
  218.         win = GetNewCWindow(wMap, nil, (WindowPtr) -1L);
  219.     } else {
  220.         win = GetNewWindow(wMap, nil, (WindowPtr) -1L);
  221.     }
  222.     map->window = win;
  223.     stagger_window(win, &lastmaph, &lastmapv);
  224.     if (first_windows) {
  225.         get_main_screen_size(&mainwidth, &mainheight);
  226.         SizeWindow(win,
  227.                    mainwidth - gamewinw - 10,
  228.                    mainheight - GetMBarHeight() - 16 - 150 - 7,
  229.                    FALSE);
  230.     }
  231.     ShowWindow(win);
  232.     SetPort(win);
  233.     sprintf(spbuf, "Map %d", mapnum++);
  234.     add_window_menu_item(spbuf, win);
  235.     set_content_rect(map);
  236.     m_center_on_focus(map);
  237.     /* Make the scrollbars. */
  238.     vscrollrect = map->window->portRect;
  239.     vscrollrect.top -= 1;
  240.     vscrollrect.bottom -= sbarwid - 1;
  241.     vscrollrect.left = vscrollrect.right - sbarwid;
  242.     vscrollrect.right += 1;
  243.     map->vscrollbar =
  244.         NewControl(win, &vscrollrect, "\p", 1,
  245.              map->vp->sy, 0, max(0, map->vp->totsh - map->vp->pxh), scrollBarProc, 0L);
  246.     hscrollrect = win->portRect;
  247.     hscrollrect.top = hscrollrect.bottom - sbarwid;
  248.     hscrollrect.bottom += 1;
  249.     hscrollrect.left += map->conw;
  250.     hscrollrect.right -= sbarwid - 1;
  251.     map->hscrollbar =
  252.         NewControl(win, &hscrollrect, "\p", 1,
  253.              map->vp->sx, 0, max(0, map->vp->totsw - map->vp->pxw), scrollBarProc, 0L);
  254.     set_map_scrollbars(map);
  255.     ++nummaps;
  256.     return map;
  257. }
  258.  
  259. /* Compute the content part of the map window. */
  260.  
  261. void
  262. set_content_rect(Map *map)
  263. {
  264.     map->contentrect = map->window->portRect;
  265.     map->contentrect.left += map->conw;  map->contentrect.top += map->toph;
  266.     map->contentrect.right -= sbarwid;  map->contentrect.bottom -= sbarwid;
  267.     set_view_size(map->vp,
  268.                   map->contentrect.right - map->contentrect.left,
  269.                   map->contentrect.bottom - map->contentrect.top);
  270.     OffsetRect(&(map->contentrect), map->vp->sx - map->conw, map->vp->sy - map->toph);
  271. }
  272.  
  273. void
  274. m_focus_on_center(Map *map)
  275. {
  276.     focus_on_center(map->vp);
  277. }
  278.  
  279. /* Put vcx,vcy in the middle of the map. */
  280.  
  281. void
  282. m_center_on_focus(Map *map)
  283. {
  284.     center_on_focus(map->vp);
  285.     set_content_rect(map);
  286. }
  287.  
  288. /* Adjust the appearance and thumb of the scroll bars to reflect the map.  This is
  289.    needed whenever the map is scrolled under program control, such as when magnifying
  290.    or scrolling to a specified location. */
  291.  
  292. void
  293. set_map_scrollbars(Map *map)
  294. {
  295.     int sx, sy, hilite;
  296.     int hexadj = hexagon_adjust(map->vp);
  297.  
  298.     sx = map->vp->sx;  sy = map->vp->sy;
  299.     if (map->vp->pxw < (map->vp->totsw - hexagon_adjust(map->vp))) {
  300.         if (sx < hexadj)
  301.           sx = hexadj;
  302.         /* Set horiz min so that leftmost cell in area is at edge of window. */
  303.         SetCtlMin(map->hscrollbar, hexadj);
  304.         /* Wrapped-around areas need extra room to look at cells on the seam. */
  305.         SetCtlMax(map->hscrollbar, map->vp->totsw - (area.xwrap ? 0 : map->vp->pxw));
  306.         SetCtlValue(map->hscrollbar, sx);
  307.         hilite = TRUE;
  308.     } else {
  309.         /* Force sx to a default value and disable the scrollbar. */
  310.         sx = hexadj;
  311.         hilite = FALSE;
  312.     }
  313.     /* Adjust the hiliting of the scrollbar, but only if the window is in front,
  314.        otherwise the scrollbar should remain unhilited. */
  315.     if (map->window == FrontWindow()) {
  316.         HiliteControl(map->hscrollbar, (hilite ? 0 : 255));
  317.     }
  318.     DGprintf("Hscroll (%shilite) is %d -- %d -- %d\n",
  319.              (hilite ? "" : "no "), GetCtlMin(map->hscrollbar),
  320.              GetCtlValue(map->hscrollbar), GetCtlMax(map->hscrollbar));
  321.     if (map->vp->pxh < map->vp->totsh) {
  322.         /* Vertical scrollbar min is always zero. */
  323.         SetCtlMax(map->vscrollbar, map->vp->totsh - map->vp->pxh);
  324.         /* Constrain the scaled y position of the map.  This keeps the computed
  325.            y from exceeding what the scroll bar will allow (which happens because
  326.            the sy calcs don't take scroll bar limits into account, should be fixed). */
  327.         if (sy > map->vp->totsh - map->vp->pxh)
  328.           sy = map->vp->totsh - map->vp->pxh;
  329.         SetCtlValue(map->vscrollbar, sy);
  330.         hilite = TRUE;
  331.     } else {
  332.         /* Force sy to the top of the map and disable the scrollbar. */
  333.         sy = 0;
  334.         hilite = FALSE;
  335.     }
  336.     if (map->window == FrontWindow()) {
  337.         HiliteControl(map->vscrollbar, (hilite ? 0 : 255));
  338.     }
  339.     set_view_position(map->vp, sx, sy);
  340.     set_content_rect(map);
  341.     DGprintf("Vscroll (%shilite) is %d -- %d -- %d\n",
  342.              (hilite ? "" : "no "), GetCtlMin(map->vscrollbar),
  343.              GetCtlValue(map->vscrollbar), GetCtlMax(map->vscrollbar));
  344. }
  345.  
  346. /* Given a magnification power, look up and/or calculate the sizes of everything,
  347.    in pixels. */
  348.  
  349. void
  350. set_map_power(Map *map, int power)
  351. {
  352.     set_view_power(map->vp, power);
  353.     if (power >= 4 && cellrgns[power] == nil)
  354.       make_cell_clip(power);
  355. }
  356.  
  357. /* Given a magnification power, compute the clipping regions to be used at
  358.    that power. */
  359.  
  360. void
  361. make_cell_clip(int power)
  362. {
  363.     int hw = hws[power], hh = hhs[power], delt = (hhs[power] - hcs[power]);
  364.     PolyHandle poly;
  365.     RgnHandle tmprgn;
  366.  
  367.     /* Make a hexagon region by drawing a polygon and then framing it while
  368.        a region is open. */
  369.     poly = OpenPoly();
  370.     MoveTo(hw / 2, 0);
  371.     LineTo(hw, delt);
  372.     LineTo(hw, hh - delt);
  373.     LineTo(hw / 2, hh);
  374.     LineTo(0, hh - delt);
  375.     LineTo(0, delt);
  376.     LineTo(hw / 2, 0);
  377.     ClosePoly();
  378.     cellrgns[power] = NewRgn();
  379.     OpenRgn();
  380.     FramePoly(poly);
  381.     CloseRgn(cellrgns[power]);
  382.     /* Make the grid-displaying version of the hexagon. */
  383.     gridcellrgns[power] = NewRgn();
  384.     CopyRgn(cellrgns[power], gridcellrgns[power]);
  385.     /* Cut off a one-pixel line on the side. */
  386.     tmprgn = NewRgn();
  387.     SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh); 
  388.     DiffRgn(gridcellrgns[power], tmprgn, gridcellrgns[power]);
  389.     /* Now intersect with a region shifted upwards by one, which makes
  390.        the grid line along the bottom of the hex. */
  391.     tmprgn = NewRgn();
  392.     CopyRgn(cellrgns[power], tmprgn);
  393.     OffsetRgn(tmprgn, 0, -1);
  394.     SectRgn(gridcellrgns[power], tmprgn, gridcellrgns[power]);
  395.  
  396.     /* Similarly, but for cells at an angle. */
  397.     /* (should only calc when angle view first requested) */
  398.     /* First make a region as viewed at a 30-degree angle. */
  399.     hh /= 2;  delt /= 2;
  400.     poly = OpenPoly();
  401.     MoveTo(hw / 2, 0);
  402.     LineTo(hw, delt);
  403.     LineTo(hw, hh - delt);
  404.     LineTo(hw / 2, hh);
  405.     LineTo(0, hh - delt);
  406.     LineTo(0, delt);
  407.     LineTo(hw / 2, 0);
  408.     ClosePoly();
  409.     cellrgns30[power] = NewRgn();
  410.     OpenRgn();
  411.     FramePoly(poly);
  412.     CloseRgn(cellrgns30[power]);
  413.     gridcellrgns30[power] = NewRgn();
  414.     CopyRgn(cellrgns30[power], gridcellrgns30[power]);
  415.     /* Cut off a one-pixel line on the side. */
  416.     tmprgn = NewRgn();
  417.     SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh/2); 
  418.     DiffRgn(gridcellrgns30[power], tmprgn, gridcellrgns30[power]);
  419.     /* Now intersect with a region shifted upwards by one, which makes
  420.        the grid line along the bottom of the hex. */
  421.     tmprgn = NewRgn();
  422.     CopyRgn(cellrgns30[power], tmprgn);
  423.     OffsetRgn(tmprgn, 0, -1);
  424.     SectRgn(gridcellrgns30[power], tmprgn, gridcellrgns30[power]);
  425.  
  426.     /* Now make a region as viewed at a 15-degree angle. */
  427.     hh = hhs[power] / 4;
  428.     delt = (hhs[power] - hcs[power]) / 4;
  429.     poly = OpenPoly();
  430.     MoveTo(hw / 2, 0);
  431.     LineTo(hw, delt);
  432.     LineTo(hw, hh - delt);
  433.     LineTo(hw / 2, hh);
  434.     LineTo(0, hh - delt);
  435.     LineTo(0, delt);
  436.     LineTo(hw / 2, 0);
  437.     ClosePoly();
  438.     cellrgns15[power] = NewRgn();
  439.     OpenRgn();
  440.     FramePoly(poly);
  441.     CloseRgn(cellrgns15[power]);
  442.     gridcellrgns15[power] = NewRgn();
  443.     CopyRgn(cellrgns15[power], gridcellrgns15[power]);
  444.     /* Cut off a one-pixel line on the side. */
  445.     tmprgn = NewRgn();
  446.     SetRectRgn(tmprgn, hw - 1, 0, hw + 1, hh/2); 
  447.     DiffRgn(gridcellrgns15[power], tmprgn, gridcellrgns15[power]);
  448.     /* Now intersect with a region shifted upwards by one, which makes
  449.        the grid line along the bottom of the hex. */
  450.     tmprgn = NewRgn();
  451.     CopyRgn(cellrgns15[power], tmprgn);
  452.     OffsetRgn(tmprgn, 0, -1);
  453.     SectRgn(gridcellrgns15[power], tmprgn, gridcellrgns15[power]);
  454. }
  455.  
  456. /* Given a window, find the map that it belongs to. */
  457.  
  458. Map *
  459. map_from_window(WindowPtr window)
  460. {
  461.     Map *map;
  462.     
  463.     if (dside == NULL)
  464.       return NULL;
  465.     for_all_maps(map) {
  466.         if (map->window == window)
  467.           return map;
  468.     }
  469.     return NULL;
  470. }
  471.  
  472. /* Set the size of the map window and position its scrollbars correctly. */
  473.  
  474. void
  475. grow_map(Map *map, int w, int h)
  476. {
  477.     int oldsx = map->vp->sx, oldsy = map->vp->sy;
  478.     int oldpxw = map->vp->pxw, oldpxh = map->vp->pxh;
  479.     Rect tmprect;
  480.     WindowPtr mapwin = map->window;
  481.  
  482.     SizeWindow(mapwin, w, h, FALSE);
  483.     adjust_map_decor(map);
  484.     set_content_rect(map);
  485.     set_map_scrollbars(map);
  486.     if (map->vp->sx == oldsx && map->vp->sy == oldsy) {
  487.         if (map->vp->pxh > oldpxh) {
  488.             SetRect(&tmprect, 0, oldpxh, map->vp->pxw, map->vp->pxh);
  489.             OffsetRect(&tmprect, map->conw, map->toph);
  490.             InvalRect(&tmprect);
  491.         }
  492.         if (map->vp->pxw > oldpxw) {
  493.             SetRect(&tmprect, oldpxw, 0, map->vp->pxw, map->vp->pxh);
  494.             OffsetRect(&tmprect, map->conw, map->toph);
  495.             InvalRect(&tmprect);
  496.         }
  497.     } else {
  498.         /* Be conservative and update everything. */
  499.         InvalRect(&mapwin->portRect);
  500.     }
  501.     /* Always need to update the controls. */
  502.     SetRect(&tmprect, 0, 0, map->conw, mapwin->portRect.bottom);
  503.     InvalRect(&tmprect);
  504.     /* Always need to update the top area. */
  505.     SetRect(&tmprect, 0, 0, mapwin->portRect.right, map->toph);
  506.     InvalRect(&tmprect);
  507.     draw_related_maps(map);
  508. }
  509.  
  510. /* Map zooming actually does "rightsizing" if possible. */
  511.  
  512. void
  513. zoom_map(Map *map, int part)
  514. {
  515.     WindowPtr mapwin = map->window;
  516.  
  517.     if (part == inZoomOut) {
  518.         set_standard_state(mapwin,
  519.                            area.width * map->vp->hw + map->conw + sbarwid + 1,
  520.                            area.height * map->vp->hch + (map->vp->hh - map->vp->hch)
  521.                              + sbarwid + map->toph + 1);
  522.     }
  523.     EraseRect(&mapwin->portRect);
  524.     ZoomWindow(mapwin, part, true);
  525.     adjust_map_decor(map);
  526.     set_content_rect(map);
  527.     /* (should try to minimize redraw here too) */
  528.     InvalRect(&mapwin->portRect);
  529. }
  530.  
  531. /* Move and size the controls to be correct for the map. */
  532.  
  533. void
  534. adjust_map_decor(Map *map)
  535. {                
  536.     int w, h;
  537.     WindowPtr mapwin = map->window;
  538.  
  539.     w = mapwin->portRect.right - mapwin->portRect.left;
  540.     h = mapwin->portRect.bottom - mapwin->portRect.top;
  541. /*    HideControl(map->hscrollbar); */
  542.     MoveControl(map->hscrollbar, map->conw - 1, h - sbarwid);
  543.     SizeControl(map->hscrollbar, w - map->conw - sbarwid + 2, sbarwid + 1);
  544. /*    HideControl(map->vscrollbar); */
  545.     MoveControl(map->vscrollbar, w - sbarwid, -1);
  546.     SizeControl(map->vscrollbar, sbarwid + 1, h - sbarwid + 1 + 1);
  547. }
  548.  
  549. /* Given a map and a cell, compute the pixel coords of the cell's UL corner.
  550.    This is the core routine that relates cells and pixels. */
  551.  
  552. void
  553. xform(map, x, y, sxp, syp)
  554. Map *map;
  555. int x, y, *sxp, *syp;
  556. {
  557.     xform_cell(map->vp, x, y, sxp, syp);
  558.     /* Shift the basic viewport result to account for both origin-shift and map decor. */
  559.     *sxp += map->osx + map->conw;  *syp += map->osy + map->toph;
  560. }
  561.  
  562. void
  563. m_xform_unit(map, unit, sxp, syp, swp, shp)
  564. Map *map;
  565. Unit *unit;
  566. int *sxp, *syp, *swp, *shp;
  567. {
  568.     xform_unit(map->vp, unit, sxp, syp, swp, shp);
  569.     /* Shift the basic viewport result to account for both origin-shift and map decor. */
  570.     *sxp += map->osx + map->conw;  *syp += map->osy + map->toph;
  571. }
  572.  
  573. void
  574. m_xform_unit_self(map, unit, sxp, syp, swp, shp)
  575. Map *map;
  576. Unit *unit;
  577. int *sxp, *syp, *swp, *shp;
  578. {
  579.     xform_unit_self(map->vp, unit, sxp, syp, swp, shp);
  580.     /* Shift the basic viewport result to account for both origin-shift and map decor. */
  581.     *sxp += map->osx + map->conw;  *syp += map->osy + map->toph;
  582. }
  583.  
  584. void
  585. m_xform_occupant(map, transport, unit, sx, sy, sw, sh, sxp, syp, swp, shp)
  586. Map *map;
  587. Unit *transport, *unit;
  588. int sx, sy, sw, sh, *sxp, *syp, *swp, *shp;
  589. {
  590.     /* Transform the coordinates back to relative values. */
  591.     sx -= map->osx + map->conw;  sy -= map->osy + map->toph;
  592.     xform_occupant(map->vp, transport, unit, sx, sy, sw, sh, sxp, syp, swp, shp);
  593.     /* Shift the basic viewport result to account for both origin-shift and map decor. */
  594.     *sxp += map->osx + map->conw;  *syp += map->osy + map->toph;
  595. }
  596.  
  597. /* Un-transform screen coordinates (as supplied by mouse perhaps) into
  598.    map coordinates.  */
  599.  
  600. /* Note that only drawing is affected by SetOrigin - mouse locations are
  601.    always window-relative, and thus only need to be adjusted by map decor
  602.    before going to the generic routines. */
  603.  
  604. int
  605. m_nearest_cell(Map *map, int sx, int sy, int *xp, int *yp)
  606. {
  607.     return nearest_cell(map->vp, sx - map->conw, sy - map->toph, xp, yp);
  608. }
  609.  
  610. /* Find the closest direction of the closest boundary.  */
  611.  
  612. int
  613. m_nearest_boundary(Map *map, int sx, int sy, int *xp, int *yp, int *dirp)
  614. {
  615.     return nearest_boundary(map->vp, sx - map->conw, sy - map->toph, xp, yp, dirp);
  616. }
  617.  
  618. int
  619. m_nearest_unit(Map *map, int sx, int sy, Unit **unitp)
  620. {
  621.     return nearest_unit(map->vp, sx - map->conw, sy - map->toph, unitp);
  622. }
  623.  
  624. /* Display a map and all of its paraphernalia. */
  625.  
  626. void
  627. draw_map(Map *map)
  628. {
  629.     Rect tmprect;
  630.     WindowPtr mapwin = map->window;
  631.     RgnHandle tmprgn;
  632.  
  633.     BackPat(QDPat(gray));
  634.     EraseRect(&(map->window->portRect));
  635.     /* Draw control panel and topline before clipping to inner part of window. */
  636.     if (map->conw > 0)
  637.       draw_control_panel(map);
  638.     if (map->toplineh > 0)
  639.       draw_top_line(map);
  640.     if (map->topunith > 0)
  641.       draw_unit_info(map);
  642.     tmprgn = NewRgn();
  643.     GetClip(tmprgn);
  644.     ClipRect(&(map->contentrect));
  645.     SHIFT_ORIGIN(map);
  646.     draw_window_background(map);
  647.     RESET_ORIGIN(map);
  648.     /* Calculate shapes and sizes. */
  649.     set_map_scrollbars(map);
  650.     set_content_rect(map);
  651.     ClipRect(&(map->contentrect));
  652.     SHIFT_ORIGIN(map);
  653.     draw_area_background(map);
  654.     draw_map_content(map);
  655.     RESET_ORIGIN(map);
  656.     if (map->drawothermaps)
  657.       draw_other_maps(map);
  658.     draw_selections(map);
  659. #ifdef DEBUGGING
  660.     /* Indicate where the focus is. */
  661.     if (DebugG) {
  662.         int sx, sy;
  663.  
  664.         ClipRect(&(map->contentrect));
  665.         SHIFT_ORIGIN(map);
  666.         xform(map, map->vp->vcx, map->vp->vcy, &sx, &sy);
  667.         SetRect(&tmprect, sx, sy, sx + map->vp->hw, sy + map->vp->hh);
  668.         InsetRect(&tmprect, -4, -4);
  669.         InvertOval(&tmprect);
  670.         InsetRect(&tmprect, 2, 2);
  671.         InvertOval(&tmprect);
  672.         RESET_ORIGIN(map);
  673.     }
  674. #endif /* DEBUGGING */
  675.     SetClip(tmprgn);
  676.     DisposeRgn(tmprgn);
  677. }
  678.  
  679. void
  680. draw_window_background(Map *map)
  681. {
  682.     /* If part of the window is entirely outside the world, we draw its shape on
  683.        top of gray, otherwise window starts out all white. */
  684.     if (area.width * map->vp->hw < 32000) {
  685.         switch (bggray) {
  686.             case blackgray:
  687.                 FillRect(&(map->contentrect), QDPat(black));  break;
  688.             case darkgray:
  689.                 FillRect(&(map->contentrect), QDPat(dkGray));  break;
  690.             case mediumgray:
  691.                 FillRect(&(map->contentrect), QDPat(gray));  break;
  692.             case lightgray:
  693.                 FillRect(&(map->contentrect), QDPat(ltGray));  break;
  694.             case whitegray:
  695.                 FillRect(&(map->contentrect), QDPat(white));  break;
  696.         }
  697.     } else {
  698.         if (hasColorQD) {
  699.             RGBForeColor((grid_matches_unseen ? &gridcolor : &unseencolor));
  700.             PaintRect(&(map->contentrect));
  701.             RGBForeColor(&blackcolor);
  702.         } else {
  703.             switch ((grid_matches_unseen ? gridgray : unseengray)) {
  704.                 case blackgray:
  705.                     FillRect(&(map->contentrect), QDPat(black));  break;
  706.                 case darkgray:
  707.                     FillRect(&(map->contentrect), QDPat(dkGray));  break;
  708.                 case mediumgray:
  709.                     FillRect(&(map->contentrect), QDPat(gray));  break;
  710.                 case lightgray:
  711.                     FillRect(&(map->contentrect), QDPat(ltGray));  break;
  712.                 case whitegray:
  713.                     FillRect(&(map->contentrect), QDPat(white));  break;
  714.             }
  715.         }
  716.     }
  717. }
  718.  
  719. /* Draw the actual map data.  This is basically a matter of drawing n rows of terrain,
  720.    each of an appropriate length, but it's a bit of trouble to get the number and
  721.    lengths right.  Actually, it's easy to get approximate sizes, but it's important
  722.    to try to draw as few cells as humanly possible. */
  723.  
  724. void
  725. draw_map_content(map)
  726. Map *map;
  727. {
  728.     int y1, y2, y, x1, x2, xx1, yy1, xx2, yy2;
  729.     int vx, vy, vw, vh;
  730.     int halfheight = area.halfheight;
  731.     int limitleft = FALSE, limitrite = FALSE;
  732.     Rect bbox = (*(map->window->visRgn))->rgnBBox;
  733.     Rect tmprect = map->contentrect;
  734.  
  735.     if (DebugG) {
  736.         FillRgn(map->window->visRgn, QDPat(white));
  737.     }
  738.     /* Compute the size of the viewport.  Make sure it will extend past the edges
  739.        of the window, so that partial cells around the edges will be filled in. */
  740.     vw = min(area.width, map->vp->pxw / map->vp->hw + 2);
  741.     vh = min(area.height, map->vp->pxh / map->vp->hch + 2);
  742.     /* Compute the bottom visible row. */
  743.     vy = ((map->vp->totsh - map->vp->sy) / map->vp->hch) - vh;
  744.     /* Now adjust the bottom row so it doesn't go outside the area. */
  745.     if (vy < 0)
  746.       vy = 0;
  747.     if (vy > area.height - vh)
  748.       vy = area.height - vh;
  749.     /* Compute the leftmost "column". */
  750.     vx = map->vp->sx / map->vp->hw - vy / 2 - 1;
  751.     DGprintf("Set %dx%d viewport at %d,%d\n", vw, vh, vx, vy);
  752.     /* Compute top and bottom rows to be displayed. */
  753.     y1 = min(vy + vh, area.height - 1);
  754.     y2 = vy;
  755.     /* Find the top and bottom rows that are in the visRgn. */
  756.     OffsetRect(&bbox, - map->vp->sx, - map->vp->sy);
  757.     if (m_nearest_cell(map, bbox.left, bbox.top, &xx1, &yy1))
  758.       limitleft = TRUE;
  759.     if (m_nearest_cell(map, bbox.right + map->vp->hw, bbox.bottom + map->vp->hh, &xx2, &yy2))
  760.       limitrite = TRUE;
  761.     xx2 += 5;
  762.     /* This fixes problem of missing rows - wish I knew why it worked :-( */
  763.     yy2 -= 10;
  764.     DGprintf("Map rows are %d - %d, update area rows are %d - %d\n", y2, y1, yy2, yy1);
  765.     if (between(y2, yy1, y1))
  766.       y1 = yy1; 
  767.     if (between(y2, yy2, y1))
  768.       y2 = yy2;
  769.     /* Draw the rows, going from top to bottom. */
  770.     for (y = y1; y >= y2; --y) {
  771.         /* Adjust the right and left bounds to fill the viewport as
  772.            much as possible, without going too far (the drawing code
  773.            will clip, but clipped drawing is still expensive). */
  774.         /* could test by drawing viewport rect as lines... */
  775.         x1 = vx - (y - vy) / 2;
  776.         x2 = x1 + vw + 2;
  777.         /* If the area doesn't wrap, then we might have to stop
  778.            drawing before we reach the edge of the viewport. */
  779.         if (area.xwrap) {
  780.             /* (should clip to visrgn, but tricky to avoid wrapping bugs) */
  781.         } else {
  782.             /* Truncate x's to stay within the area. */
  783.             x1 = max(0, min(x1, area.width-1));
  784.             x2 = max(0, min(x2, area.width));
  785.             /* If this row is entirely in the NE corner, don't draw anything. */
  786.             if (x1 + y > area.width + halfheight)
  787.               continue;
  788.             /* If this row is entirely in the SW corner, don't draw anything. */
  789.             if (x2 + y < halfheight)
  790.               continue;
  791.             /* If the row ends up in the NE corner, shorten it. */
  792.             if (x2 + y > area.width + halfheight)
  793.               x2 = area.width + halfheight - y;
  794.             /* If the row starts out in the SW corner, shorten it. */
  795.             if (x1 + y < halfheight)
  796.               x1 = halfheight - y;
  797.             /* Clip the ends of the row to the visRgn. */
  798.             if (limitleft && between(x1, xx1, x2))
  799.               x1 = xx1; 
  800.             if (limitrite && between(x1, xx2, x2))
  801.               x2 = xx2;
  802.         }
  803.         draw_row(map, x1, y, x2 - x1, FALSE);
  804.     }
  805. }
  806.  
  807. /* This draws a hexagon or rectangle that covers the totality of the area, whether
  808.    discovered or not. */
  809.  
  810. void 
  811. draw_area_background(Map *map)
  812. {
  813.     int sx, sy, llx, lly, lrx, lry, rx, ry, urx, ury, ulx, uly, lx, ly;
  814.     PolyHandle poly;
  815.     Rect arearect;
  816.  
  817.     /* Don't bother if area magnified greatly. */
  818.     /* (should fix to not try to draw giant rects, but still draw something reasonable.
  819.        note that otherwise grid color may be wrong) */
  820.     if (area.width * map->vp->hw > 32000)
  821.       return;
  822.     if (area.xwrap) {
  823.         /* Area is cylinder; draw a rectangle. */
  824.         xform(map, 0, area.height-1, &sx, &sy);
  825.         arearect.left = 0;  arearect.top = sy;
  826.         xform(map, 0, 0, &sx, &sy);
  827.         arearect.right = area.width * map->vp->hw;  arearect.bottom = sy;
  828.         /* Adjust so that edges of the rect pass through the middles of edge cells. */
  829.         OffsetRect(&arearect, map->vp->hw/2, map->vp->hh/2);
  830.         if (hasColorQD) {
  831.             RGBForeColor(&gridcolor);
  832.             PaintRect(&arearect);
  833.             RGBForeColor(&blackcolor);
  834.         } else {
  835.             switch (gridgray) {
  836.                 case blackgray:
  837.                     FillRect(&arearect, QDPat(black));   break;
  838.                 case darkgray:
  839.                     FillRect(&arearect, QDPat(dkGray));  break;
  840.                 case mediumgray:
  841.                     FillRect(&arearect, QDPat(gray));    break;
  842.                 case lightgray:
  843.                     FillRect(&arearect, QDPat(ltGray));  break;
  844.                 case whitegray:
  845.                     FillRect(&arearect, QDPat(white));   break;
  846.             }
  847.         }
  848.     } else {
  849.         /* Area is hexagon; draw a hexagon. */
  850.         /* (should make once and save?) */
  851.         poly = OpenPoly();        
  852.         xform(map, 0 + area.halfheight, 0, &llx, &lly);
  853.         MoveTo(llx, lly);
  854.         xform(map, area.width-1, 0, &lrx, &lry);
  855.          LineTo(lrx, lry);
  856.         xform(map, area.width-1, area.halfheight, &rx, &ry);
  857.         LineTo(rx, ry);
  858.          xform(map, area.width-1 - area.halfheight, area.height-1, &urx, &ury);
  859.         LineTo(urx, ury);
  860.          xform(map, 0, area.height-1, &ulx, &uly);
  861.         LineTo(ulx, uly);
  862.          xform(map, 0, area.halfheight, &lx, &ly);
  863.         LineTo(lx, ly);
  864.         LineTo(llx, lly);
  865.         ClosePoly();
  866.         /* Adjust so that edges of the polygon pass through the middles of edge cells. */
  867.         OffsetPoly(poly, map->vp->hw/2, map->vp->hh/2);
  868.         if (hasColorQD) {
  869.             RGBForeColor(&gridcolor);
  870.             PaintPoly(poly);
  871.             RGBForeColor(&blackcolor);
  872.         } else {
  873.             switch (gridgray) {
  874.                 case blackgray:
  875.                     FillPoly(poly, QDPat(black));   break;
  876.                 case darkgray:
  877.                     FillPoly(poly, QDPat(dkGray));  break;
  878.                 case mediumgray:
  879.                     FillPoly(poly, QDPat(gray));    break;
  880.                 case lightgray:
  881.                     FillPoly(poly, QDPat(ltGray));  break;
  882.                 case whitegray:
  883.                     FillPoly(poly, QDPat(white));   break;
  884.             }
  885.         }
  886.         /* Free up the space for this hexagon. */
  887.         KillPoly(poly);
  888.     }
  889. #if 0  /* The idea of a shaded border seems nice, but it doesn't look very good in practice. */
  890.     for (x = 0; x < area.width; ++x) {
  891.         xform(map, x, 0, &sx, &sy);
  892.         draw_border_line(sx, sy, SW, map->vp->power, -1);
  893.         draw_border_line(sx, sy, SE, map->vp->power, -2);
  894.     }
  895.     PenNormal();
  896. #endif
  897. }
  898.  
  899. /* Draw the map control panel as a pair of PICTs. */
  900.  
  901. void
  902. draw_control_panel(map)
  903. Map *map;
  904. {
  905.     int winhgt, basev;
  906.     Rect tmprect;
  907.  
  908.     winhgt = (map->window->portRect).bottom - (map->window->portRect).top;
  909.     SetRect(&tmprect, 0, 0, map->conw, winhgt);
  910.     FillRect(&tmprect, QDPat(white));
  911.     MoveTo(map->conw - 1, 0);  Line(0, winhgt);
  912.     if (tlcontrols == nil) {
  913.         tlcontrols = (PicHandle) GetResource('PICT', pMapControlsTL);
  914.     }
  915.     if (tlcontrols != nil) {
  916.         SetRect(&tmprect, 0, 0,
  917.                 picture_width(tlcontrols), picture_height(tlcontrols));
  918.         DrawPicture(tlcontrols, &tmprect);
  919.     }
  920.     if (blcontrols == nil) {
  921.         blcontrols = (PicHandle) GetResource('PICT', pMapControlsBL);
  922.     }
  923.     if (blcontrols != nil) {
  924.         SetRect(&tmprect, 0, winhgt - picture_height(blcontrols) + 1,
  925.                 picture_width(blcontrols), winhgt);
  926.         DrawPicture(blcontrols, &tmprect);
  927.     }
  928.     if (map->moveonclick && map->autoselect) {
  929.         SetRect(&tmprect, 4, 5, 26, 26);
  930.         InvertRect(&tmprect);
  931.     }
  932.     /* (should modify appearance of top left arrow buttons to reflect abilities) */
  933.     basev = 32 + 5*15 + 2 + 5/*why?*/ + 1;
  934.     SetRect(&tmprect, 0, basev, 30, basev + 10);
  935.     if (map->drawgrid) {
  936.         InvertRect(&tmprect);
  937.     }
  938.     OffsetRect(&tmprect, 0, 11);
  939.     if (map->drawnames) {
  940.         InvertRect(&tmprect);
  941.     }
  942.     OffsetRect(&tmprect, 0, 11);
  943.     if (map->drawpeople) {
  944.         InvertRect(&tmprect);
  945.     } else if (!people_sides_defined()) {
  946.         gray_out_rect(&tmprect);
  947.     }
  948.     OffsetRect(&tmprect, 0, 11);
  949.     if (map->drawplans) {
  950.         InvertRect(&tmprect);
  951.     }
  952.     OffsetRect(&tmprect, 0, 11);
  953.     if (map->drawai) {
  954.         InvertRect(&tmprect);
  955.     } else if (!side_has_ai(dside)) {
  956.         /* (should ensure that this is updated when side gets an AI) */
  957.         gray_out_rect(&tmprect);
  958.     }
  959.     OffsetRect(&tmprect, 0, 11);
  960.     if (dside->may_set_see_all && dside->see_all) {
  961.         InvertRect(&tmprect);
  962.     } else if (!dside->may_set_see_all) {
  963.         /* (should ensure that this is updated when side gets an AI) */
  964.         gray_out_rect(&tmprect);
  965.     }
  966.     /* Draw state of bottom left control buttons. */
  967.     if (map->vp->power <= 0) {
  968.         SetRect(&tmprect, 0, winhgt - 15, 15, winhgt);
  969.         gray_out_rect(&tmprect);
  970.     }
  971.     if (map->vp->power >= NUMPOWERS - 1) {
  972.         SetRect(&tmprect, 16, winhgt - 15, 30, winhgt);
  973.         gray_out_rect(&tmprect);
  974.     }
  975. }
  976.  
  977. void
  978. draw_top_line(Map *map)
  979. {
  980.     int numchars, strwid;
  981.     Rect tmprect;
  982.  
  983.     /* Clear the whole topline area. */
  984.     SetRect(&tmprect, map->conw, 0, map->conw + map->vp->pxw, map->toplineh);
  985.     FillRect(&tmprect, QDPat(white));
  986.     /* Draw a line dividing this from the map content. */
  987.     MoveTo(tmprect.left, tmprect.bottom - 1);
  988.     Line(tmprect.right - tmprect.left, 0);
  989.     /* Draw the current date. */
  990.     TextSize(10);
  991.     strwid = TextWidth(curdatestr, 1, curdatestr[0]);
  992.     MoveTo(tmprect.right - strwid - 3, tmprect.top + 11);
  993.     numchars = curdatestr[0];
  994.     DrawText(curdatestr, 1, numchars);
  995.     if (mouseover != NULL) {
  996.         /* Draw description of what the mouse is over. */
  997.         /* (should clip to avail space) */
  998.         numchars = strlen(mouseover);
  999.         MoveTo(map->conw + 3, tmprect.top + 11);
  1000.         DrawText(mouseover, 0, numchars);
  1001.     }
  1002. }
  1003.  
  1004. void
  1005. draw_unit_info(Map *map)
  1006. {
  1007.     int mrow, u, m;
  1008.     Rect tmprect;
  1009.     Unit *unit;
  1010.     char infobuf[100];
  1011.     GrafPtr oldport;
  1012.     RgnHandle tmprgn;
  1013.  
  1014.     if (map->topunith <= 0)
  1015.       return;
  1016.      GetPort(&oldport);
  1017.     SetPort(map->window);
  1018.     /* Save the current clipping region. */
  1019.     tmprgn = NewRgn();
  1020.     GetClip(tmprgn);
  1021.     SetRect(&tmprect, map->conw, map->toplineh, map->conw + map->vp->pxw, map->toph);
  1022.     ClipRect(&tmprect);
  1023.     FillRect(&tmprect, QDPat(white));
  1024.     /* Draw a line dividing this from the map content. */
  1025.     MoveTo(tmprect.left, tmprect.bottom - 1);
  1026.     Line(tmprect.right - tmprect.left, 0);
  1027.     if (map->numselections == 1) {
  1028.         unit = map->selections[0];
  1029.         if (in_play(unit)) {
  1030.             u = unit->type;
  1031.             sprintf(infobuf, "%s", unit_handle(dside, unit));
  1032.             draw_info_text(map, 0, 0, 0, infobuf);
  1033.             location_desc(infobuf, dside, unit, unit->type, unit->x, unit->y);
  1034.             draw_info_text(map, 0, 1, 0, infobuf);
  1035.             hp_desc(infobuf, unit, TRUE);
  1036.             strcat(infobuf, "   ");
  1037.             acp_desc(tmpbuf, unit, TRUE);
  1038.             strcat(infobuf, tmpbuf);
  1039.             draw_info_text(map, 50, 0, 0, infobuf);
  1040.             mrow = 0;
  1041.             while (supply_desc(infobuf, unit, mrow)) {
  1042.                 draw_info_text(map, 50, mrow + 1, 0, infobuf);
  1043.                 ++mrow;
  1044.             }
  1045.             /* Describe the current plan and task agenda. */
  1046.             if (unit->plan) {
  1047.                 int row = 2;
  1048.                 Task *task;
  1049.  
  1050.                 plan_desc(infobuf, unit);
  1051.                 draw_info_text(map, 0, row++, 0, infobuf);
  1052.                 for_all_tasks(unit->plan, task) {
  1053.                     task_desc(infobuf, task);
  1054.                     draw_info_text(map, 0, row++, 0, infobuf);
  1055.                 }
  1056.             }
  1057.         }
  1058.     } else if (map->numselections > 1) {
  1059.         draw_info_text(map, 0, 0, 0, "(multiple units)");
  1060.     }
  1061.     /* Restore clipping region. */
  1062.     SetClip(tmprgn);
  1063.     DisposeRgn(tmprgn);
  1064.     /* Restore grafport. */
  1065.     SetPort(oldport);
  1066. }
  1067.  
  1068. static void
  1069. draw_info_text(map, x, y, len, buf)
  1070. Map *map;
  1071. int x, y, len;
  1072. char *buf;
  1073. {
  1074.     int sx, sy;
  1075.     Rect tmprect;
  1076.  
  1077.     SetRect(&tmprect, map->conw, map->toplineh, map->conw + map->vp->pxw, map->toph);
  1078.     /* Translate a 0-100 value for x to pixels. */
  1079.     if (x == 50)
  1080.       sx = tmprect.left + (tmprect.right - tmprect.left) / 2;
  1081.     else
  1082.       sx = tmprect.left + 3;
  1083.     sy = tmprect.top + 11 + y * 15;
  1084.     if (len > 0 && strlen(buf) > len)
  1085.       buf[len-1] = '\0';
  1086.     MoveTo(sx, sy);
  1087.     DrawText(buf, 0, strlen(buf));
  1088. }
  1089.  
  1090. /* Draw an indication of the position of other maps relative to this one. */
  1091.  
  1092. void
  1093. draw_other_maps(map)
  1094. Map *map;
  1095. {
  1096.     Map *map2;
  1097.  
  1098.     for_all_maps(map2) {
  1099.         if (map != map2 /* && reasonable to show? */) {
  1100.             draw_other_map(map, map2);
  1101.         }
  1102.     }
  1103. }
  1104.  
  1105. void
  1106. draw_related_maps(map)
  1107. Map *map;
  1108. {
  1109.     Map *map2;
  1110.     GrafPtr oldport;
  1111.  
  1112.     for_all_maps(map2) {
  1113.         if (map != map2 && map2->drawothermaps /* && reasonable to show? */) {
  1114.             GetPort(&oldport);
  1115.             SetPort(map2->window);
  1116.             /* (also clipping?) */
  1117.             draw_other_map(map2, map);
  1118.             SetPort(oldport);
  1119.         }
  1120.     }
  1121. }
  1122.  
  1123. void
  1124. draw_other_map(map, map2)
  1125. Map *map, *map2;
  1126. {
  1127.     int sx, sy, sw, sh;
  1128.     Rect tmprect;
  1129.  
  1130.     scale_vp(map->vp, map2->vp, &sx, &sy, &sw, &sh);
  1131.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  1132.     OffsetRect(&tmprect, map->conw, map->toph);
  1133.     if (map->vp->hw < 8) PenSize(2, 2);
  1134.     PenMode(patXor);
  1135.     FrameRect(&tmprect);
  1136.     PenNormal();
  1137. }
  1138.  
  1139. /* x0 may be negative here. */
  1140.  
  1141. /* (should add a "draw interior only" version of this routine?) */
  1142.  
  1143. void
  1144. draw_row(map, x0, y0, len, clearit)
  1145. Map *map;
  1146. int x0, y0, len, clearit;
  1147. {
  1148.     int empty = FALSE;
  1149.     int i = 0, x, xw, sx, sy, t;
  1150.  
  1151.     if (!between(0, y0, area.height - 1))
  1152.       return;
  1153.     if (!dside->see_all && !map->drawai && unseen_image == NULL) {
  1154.         empty = TRUE;
  1155.         /* Examine row to see if we can skip it entirely. */
  1156.         for (x = x0; x < x0 + len; ++x) {
  1157.             xw = wrapx(x);
  1158.             if (terrain_visible(dside, xw, y0)
  1159.                 || (numbordtypes > 0 && terrain_visible(dside, xw, y0 + 1))
  1160.                 ) {
  1161.                 empty = FALSE;
  1162.                 break;
  1163.             }
  1164.         }
  1165.     }
  1166.     if (empty && !clearit)
  1167.       return;
  1168.     /* The terrain always comes first. */
  1169.     if (map->drawterrain) {
  1170.         draw_terrain_row(map, x0, y0, len);
  1171.         /* Maybe draw cliffs. */
  1172.         if (elevations_defined() && map->vp->angle != 90 && y0 > 0) {
  1173.             for (x = x0; x < x0 + len; ++x) {
  1174.                 if (terrain_visible(dside, x, y0)) {
  1175.                     draw_cliffs(map, x, y0);
  1176.                 }
  1177.             }
  1178.         }
  1179.         if (elevations_defined() && map->drawelevations && map->vp->angle == 90) {
  1180.             for (x = x0; x < x0 + len; ++x) {
  1181.                 if (terrain_visible(dside, x, y0)) {
  1182.                     draw_contours(map, x, y0);
  1183.                 }
  1184.             }
  1185.         }
  1186.         if (any_aux_terrain_defined()) {
  1187.             /* The relative ordering of these is quite important - connections
  1188.                should always be drawn on top of borders. */
  1189.             if (bords_to_draw(map)) {
  1190.                 for_all_terrain_types(t) {
  1191.                     if (map->drawauxterrain[t] && t_is_border(t) && aux_terrain_defined(t)) {
  1192.                         for (x = x0; x < x0 + len; ++x) {
  1193.                             draw_borders(map, x, y0, t);
  1194.                         }
  1195.                     }
  1196.                 }
  1197.             }
  1198.             if (conns_to_draw(map)) {
  1199.                 for_all_terrain_types(t) {
  1200.                     if (map->drawauxterrain[t] && t_is_connection(t) && aux_terrain_defined(t)) {
  1201.                         for (x = x0; x < x0 + len; ++x) {
  1202.                             draw_connections(map, x, y0, t);
  1203.                         }
  1204.                     }
  1205.                 }
  1206.             }
  1207.         }
  1208.     }
  1209.     /* Although we had to draw the terrain on the edge, we can skip everything else,
  1210.        since edge cells have no units, weather, etc. */
  1211.     /* Skip the top and bottom edge rows. */
  1212.     if (!between(1, y0, area.height - 2)) 
  1213.       return;
  1214.     /* Shorten the row by one cell on each side, if those are edge cells. */
  1215.     if (!inside_area(x0 + len - 1, y0))
  1216.       --len;
  1217.     if (!inside_area(x0, y0)) {
  1218.         ++x0;
  1219.         --len;
  1220.     }
  1221.     if (len <= 0)
  1222.       return;
  1223.     if (any_cell_materials_defined() && map->nummaterialstodraw > 0 && map->vp->hh > 20) {
  1224.         for (x = x0; x < x0 + len; ++x) {
  1225.             draw_materials(map, x, y0);
  1226.         }
  1227.     }
  1228.     /* (should be global to entire map drawing somehow?) */
  1229.     if (map->drawnames && map->vp->hh > 5) {
  1230.         for (x = x0; x < x0 + len; ++x) {
  1231.             draw_legend(map, x, y0);
  1232.         }
  1233.     }
  1234.     if (people_sides_defined() && bwid2[map->vp->power] > 0) {
  1235.         draw_people_row(map, x0, y0, len);
  1236.     }
  1237.     if (map->drawunits && map->vp->hw > 2) {
  1238.         for (x = x0; x < x0 + len; ++x) {
  1239.             draw_units(map, x, y0);
  1240.         }
  1241.     }
  1242.     if (map->drawai) {
  1243.         for (x = x0; x < x0 + len; ++x) {
  1244.             draw_ai_region(map, x, y0);
  1245.         }
  1246.     }
  1247.     /* If debugging, draw coverage on top of everything else. */
  1248.     if (DebugG && !all_see_all && map->vp->hw >= 16) {
  1249.         for (x = x0; x < x0 + len; ++x) {
  1250.             xform(map, x, y0, &sx, &sy);
  1251.             draw_coverage(sx, sy, map->vp->power, cover(dside, x, y0), alt_cover(dside, x, y0));
  1252.         }
  1253.     }
  1254. }
  1255.  
  1256. /* Is this just to see if a cell is visible? */
  1257.  
  1258. int
  1259. cell_update(map, x, y)
  1260. Map *map;
  1261. int x, y;
  1262. {
  1263. #if 0
  1264.     int sx, sy;
  1265.     Rect tmprect;
  1266.  
  1267.     xform(map, x, y, &sx, &sy);
  1268.     SetRect(&tmprect, sx, sy, sx + map->vp->hw, sy + map->vp->hh);
  1269.     return (RectInRgn(&tmprect, map->window->visRgn));
  1270. #else
  1271.     return TRUE;
  1272. #endif
  1273. }
  1274.  
  1275. /* Draw an entire row of terrain, possibly with a single rectangle fill. */
  1276.  
  1277. /* x0 may be negative. */
  1278.  
  1279. extern int sunx, suny;
  1280.  
  1281. void
  1282. draw_terrain_row(map, x0, y0, len)
  1283. Map *map;
  1284. int x0, y0, len;
  1285. {
  1286.     int x0w, x, xw, x1, x1w, sx, sy, i;
  1287.     int pwr = map->vp->power, ang = map->vp->angle;
  1288.     int dogrid = map->drawgrid, dofill = map->drawcellpats;
  1289.     int inarea, seginarea, style, segstyle, terr, segterr, over, segover, update, segupdate;
  1290.  
  1291.     tmpdrawlighting = map->drawlighting;
  1292.     tmpdrawcoverage = (!all_see_all && map->drawcover);
  1293.     x0w = wrapx(x0);
  1294.     i = 0;
  1295.     x1 = x0;
  1296.     x1w = wrapx(x1);
  1297.     seginarea = in_area(x0w, y0);
  1298.     segstyle = cell_style(x0w, y0, pwr);
  1299.     segterr = cell_terrain(x0w, y0, pwr);
  1300.     segover = cell_overlay(x0w, y0);
  1301.     segupdate = (seginarea ? cell_update(map, x0w, y0) : FALSE);
  1302.     for (x = x0; x < x0 + len + 1; ++x) {
  1303.         xw = wrapx(x);
  1304.         inarea = in_area(xw, y0);
  1305.         style = cell_style(xw, y0, pwr);
  1306.         terr = cell_terrain(xw, y0, pwr);
  1307.         over = cell_overlay(xw, y0);
  1308.         update = (inarea ? cell_update(map, xw, y0) : FALSE);
  1309.         /* Decide if the run is over and we need to dump some output. */
  1310.         if (x == x0 + len
  1311.             || inarea != seginarea
  1312.             || style != segstyle
  1313.             || terr != segterr
  1314.             || over != segover
  1315.             || update != segupdate
  1316. /*            || segstyle == useblocks  fixes, but poor performance */
  1317.             || segstyle == usepictures
  1318.             || segstyle == usepolygons
  1319.             || ang != 90) {
  1320.             /* don't draw anything that would match the window's bg */
  1321. #if 0 /* use this for heavy-duty debugging only */
  1322.             DGprintf("Seg is %d,%d len=%d inarea=%d style=%d terr=%d over=%d update=%d\n",
  1323.                      x1, y0, i, seginarea, segstyle, segterr, segover, segupdate);
  1324. #endif
  1325.             if (seginarea && segupdate && segstyle != dontdraw) {
  1326.                 xform(map, x1, y0, &sx, &sy);
  1327.                 if (area.xwrap && sx > map->vp->totsw)
  1328.                   sx -= map->vp->totsw;
  1329.                 switch (segstyle) {
  1330.                     case useblocks:
  1331.                         draw_cell_block(sx, sy, i, pwr, segterr, segover, ang);
  1332.                         break;
  1333.                     case usepictures:
  1334.                         break;
  1335.                     case usepolygons:
  1336.                         draw_hex_region(sx, sy, pwr, map->drawgrid, segterr, segover, ang);
  1337.                         /* Assume that only polygon scale can fit numbers. */
  1338.                         if (0 && elevations_defined()
  1339.                             && map->drawelevations
  1340.                             && draw_elevation_here(x1w, y0)) {
  1341.                             draw_elevation(sx, sy, pwr, elev_at(x1w, y0));
  1342.                         }
  1343.                         if (clouds_defined()
  1344.                             && map->drawclouds
  1345.                             && draw_clouds_here(x1w, y0)) {
  1346.                             draw_clouds(sx, sy, pwr, cloud_view(dside, x1w, y0));
  1347.                         }
  1348.                         if (winds_defined()
  1349.                             && map->drawwinds
  1350.                             && draw_winds_here(x1w, y0)) {
  1351.                             draw_winds(sx, sy, pwr, wind_view(dside, x1w, y0));
  1352.                         }
  1353.                         if (temperatures_defined()
  1354.                             && map->drawtemperature
  1355.                             && draw_temperature_here(x1w, y0)) {
  1356.                             draw_temperature(sx, sy, pwr, temperature_view(dside, x1w, y0));
  1357.                         }
  1358.                 }
  1359.             }
  1360.             /* Set up for the next segment. */
  1361.             i = 0;
  1362.             x1 = x;
  1363.             x1w = wrapx(x1);
  1364.             seginarea = inarea;
  1365.             segstyle = style;
  1366.             segterr = terr;
  1367.             segover = over;
  1368.             segupdate = update;
  1369.         }
  1370.         ++i;
  1371.     }
  1372. }
  1373.  
  1374. static void
  1375. draw_cliffs(Map *map, int x, int y)
  1376. {
  1377.     int elev, x1, y1, drop, t, t1;
  1378.     int sx, sy, sx1, sy1;
  1379.     PolyHandle poly;
  1380.     RGBColor hexcolor, oldcolor;
  1381.  
  1382.     t = cell_terrain(x, y, map->vp->power);
  1383.     elev = elev_at(x, y) + t_thickness(t);
  1384.     if (point_in_dir(x, y, SOUTHWEST, &x1, &y1)) {
  1385.         t1 = cell_terrain(x1, y1, map->vp->power);
  1386.         if (t1 != NONTTYPE) {
  1387.           drop = elev - (elev_at(x1, y1) + t_thickness(t1));
  1388.           if (drop > 0) {
  1389.             xform(map, x, y, &sx, &sy);
  1390.             xform(map, x1, y1, &sx1, &sy1);
  1391.             if (sy1 > sy + map->vp->hch + (map->drawgrid ? 1 : 0)) {
  1392.                 poly = OpenPoly();
  1393.                 MoveTo(sx, sy + map->vp->hch);
  1394.                 LineTo(sx + map->vp->hw / 2, sy + map->vp->hh);
  1395.                 LineTo(sx + map->vp->hw / 2, sy1 + (map->vp->hh - map->vp->hch));
  1396.                 LineTo(sx, sy1);
  1397.                 LineTo(sx, sy + map->vp->hch);
  1398.                 ClosePoly();
  1399.                 /* if (timg->colrpat != nil
  1400.                     && (minscreendepth > 1 || !timg->patdefined)) {
  1401.                     FillCPoly(poly, timg->colrpat);
  1402.                 } else */ if (tcolors[t] != NULL && tcolors[t]->defined && maxscreendepth > 1) {
  1403.                     hexcolor.red   = (tcolors[t]->r / 2) << 8;
  1404.                     hexcolor.green = (tcolors[t]->g / 2) << 8;
  1405.                     hexcolor.blue  = (tcolors[t]->b / 2) << 8;
  1406.                     RGBForeColor(&hexcolor);
  1407.                     PaintPoly(poly);
  1408.                     /* Restore the previous color. */
  1409.                     oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  1410.                     RGBForeColor(&oldcolor);
  1411.                 } else {
  1412.                     hexcolor.red   = 128 << 8;
  1413.                     hexcolor.green = 128 << 8;
  1414.                     hexcolor.blue  = 128 << 8;
  1415.                     RGBForeColor(&hexcolor);
  1416.                     PaintPoly(poly);
  1417.                     /* Restore the previous color. */
  1418.                     oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  1419.                     RGBForeColor(&oldcolor);
  1420.                 }
  1421.                 KillPoly(poly);
  1422.             }
  1423.           }
  1424.         }
  1425.     }
  1426.     if (point_in_dir(x, y, SOUTHEAST, &x1, &y1)) {
  1427.         t1 = cell_terrain(x1, y1, map->vp->power);
  1428.         if (t1 != NONTTYPE) {
  1429.           drop = elev - (elev_at(x1, y1) + t_thickness(t1));
  1430.           if (drop > 0) {
  1431.             xform(map, x, y, &sx, &sy);
  1432.             xform(map, x1, y1, &sx1, &sy1);
  1433.             if (sy1 > sy + map->vp->hch + (map->drawgrid ? 1 : 0)) {
  1434.                 poly = OpenPoly();
  1435.                 MoveTo(sx + map->vp->hw - (map->drawgrid ? 1 : 0),     sy + map->vp->hch);
  1436.                 LineTo(sx + map->vp->hw - (map->drawgrid ? 1 : 0),     sy1);
  1437.                 LineTo(sx + map->vp->hw / 2, sy1 + (map->vp->hh - map->vp->hch));
  1438.                 LineTo(sx + map->vp->hw / 2, sy + map->vp->hh);
  1439.                 LineTo(sx + map->vp->hw - (map->drawgrid ? 1 : 0),     sy + map->vp->hch);
  1440.                 ClosePoly();
  1441.                 /* if (timg->colrpat != nil
  1442.                     && (minscreendepth > 1 || !timg->patdefined)) {
  1443.                     FillCPoly(poly, timg->colrpat);
  1444.                 } else */ if (tcolors[t] != NULL && tcolors[t]->defined && maxscreendepth > 1) {
  1445.                     hexcolor.red   = (tcolors[t]->r) << 8;
  1446.                     hexcolor.green = (tcolors[t]->g) << 8;
  1447.                     hexcolor.blue  = (tcolors[t]->b) << 8;
  1448.                     RGBForeColor(&hexcolor);
  1449.                     PaintPoly(poly);
  1450.                     /* Restore the previous color. */
  1451.                     oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  1452.                     RGBForeColor(&oldcolor);
  1453.                 } else {
  1454.                     hexcolor.red   = 128 << 8;
  1455.                     hexcolor.green = 128 << 8;
  1456.                     hexcolor.blue  = 128 << 8;
  1457.                     RGBForeColor(&hexcolor);
  1458.                     PaintPoly(poly);
  1459.                     /* Restore the previous color. */
  1460.                     oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  1461.                     RGBForeColor(&oldcolor);
  1462.                 }
  1463.                 KillPoly(poly);
  1464.             }
  1465.           }
  1466.         }
  1467.     }
  1468. }
  1469.  
  1470. /* The theory of contour lines is that each hex can be considered as
  1471.    six triangles, each of which has a vertex at the center and two
  1472.    on adjacent corners of the hex.  The elevation of the center vertex
  1473.    is the overall elevation of the cell, the elevations of the corners
  1474.    are averages with the adjacent cells.  If a particular contour
  1475.    elevation is between any pair of vertex elevations, then the contour
  1476.    line must cross that side of the triangle - and one of the other two
  1477.    sides.  We decide which of the two it is, interpolate to get the
  1478.    actual positions of each endpoint of the line segment, then draw it. */
  1479.  
  1480. int num_contours;
  1481.  
  1482. int contour_interval = -1;
  1483.  
  1484. static void
  1485. draw_contours(Map *map, int x, int y)
  1486. {
  1487.     int el, dir, x1, y1, sum, n, lowest, liq, ecor[NUMDIRS], ec;
  1488.     int sx, sy, sxcor[NUMDIRS], sycor[NUMDIRS], sxc, syc;
  1489.     int power = map->vp->power;
  1490.     int ecorr, ecorl, sxcorr, sycorr, sxcorl, sycorl;
  1491.     int sx1, sy1, sx2, sy2;
  1492.  
  1493.     if (contour_interval < 0) {
  1494.         /* (should be user-settable map parm) */
  1495.         num_contours = min(20, area.maxelev - area.minelev);
  1496.         contour_interval = (area.maxelev - area.minelev) / num_contours;
  1497.     }
  1498.     if (contour_interval < 1)
  1499.       return;
  1500.     el = elev_at(x, y);
  1501.     xform(map, x, y, &sx, &sy);
  1502.     sxc = sx + map->vp->hw / 2;  syc = sy + map->vp->hh / 2;
  1503.     for_all_directions(dir) {
  1504.         sum = el;
  1505.         n = 1;
  1506.         lowest = el;
  1507.         liq = t_liquid(terrain_at(x, y));
  1508.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  1509.             sum += elev_at(x1, y1);
  1510.             ++n;
  1511.             lowest = min(lowest, elev_at(x1, y1));
  1512.             if (t_liquid(terrain_at(x1, y1)))
  1513.               liq = TRUE;
  1514.         }
  1515.         if (point_in_dir(x, y, left_dir(dir), &x1, &y1)) {
  1516.             sum += elev_at(x1, y1);
  1517.             ++n;
  1518.             lowest = min(lowest, elev_at(x1, y1));
  1519.             if (t_liquid(terrain_at(x1, y1)))
  1520.               liq = TRUE;
  1521.         }
  1522.         if (liq)
  1523.           ecor[dir] = lowest;
  1524.         else
  1525.           ecor[dir] = sum / n;
  1526.         sxcor[dir] = sx + bsx[power][dir];  sycor[dir] = sy + bsy[power][dir];
  1527.     }
  1528.     for (ec = area.minelev + contour_interval; ec < area.maxelev; ec += contour_interval) {
  1529.         for_all_directions(dir) {
  1530.             ecorr = ecor[dir];
  1531.             ecorl = ecor[left_dir(dir)];
  1532.             sxcorr = sxcor[dir];  sycorr = sycor[dir];
  1533.             sxcorl = sxcor[left_dir(dir)];  sycorl = sycor[left_dir(dir)];
  1534.             if (el != ecorr && between(min(el, ecorr), ec, max(el, ecorr))) {
  1535.                 sx1 = sxc + ((sxcorr - sxc) * (ec - el)) / (ecorr - el);
  1536.                 sy1 = syc + ((sycorr - syc) * (ec - el)) / (ecorr - el);
  1537.                 if (el != ecorl && between(min(el, ecorl), ec, max(el, ecorl))) {
  1538.                     sx2 = sxc + ((sxcorl - sxc) * (ec - el)) / (ecorl - el);
  1539.                     sy2 = syc + ((sycorl - syc) * (ec - el)) / (ecorl - el);
  1540.                     MoveTo(sx1, sy1);
  1541.                     LineTo(sx2, sy2);
  1542.                 } else if (ecorl != ecorr) {
  1543.                     sx2 = sxcorr + ((sxcorl - sxcorr) * (ec - ecorr)) / (ecorl - ecorr);
  1544.                     sy2 = sycorr + ((sycorl - sycorr) * (ec - ecorr)) / (ecorl - ecorr);
  1545.                     MoveTo(sx1, sy1);
  1546.                     LineTo(sx2, sy2);
  1547.                 }
  1548.             }
  1549.             if (el != ecorl && between(min(el, ecorl), ec, max(el, ecorl))) {
  1550.                 sx1 = sxc + ((sxcorl - sxc) * (ec - el)) / (ecorl - el);
  1551.                 sy1 = syc + ((sycorl - syc) * (ec - el)) / (ecorl - el);
  1552.                 if (ecorl != ecorr && between(min(ecorr, ecorl), ec, max(ecorr, ecorl))) {
  1553.                     sx2 = sxcorr + ((sxcorl - sxcorr) * (ec - ecorr)) / (ecorl - ecorr);
  1554.                     sy2 = sycorr + ((sycorl - sycorr) * (ec - ecorr)) / (ecorl - ecorr);
  1555.                     MoveTo(sx1, sy1);
  1556.                     LineTo(sx2, sy2);
  1557.                 }
  1558.             }
  1559.         }
  1560.     }
  1561. }
  1562.  
  1563. static void
  1564. draw_borders(map, x, y, b)
  1565. Map *map;
  1566. int x, y, b;
  1567. {
  1568.     int xw = wrapx(x), dir, sx, sy, bitmask = 0;
  1569.     
  1570.      if (!terrain_visible(dside, xw, y) || !any_borders_at(x, y, b))
  1571.        return;
  1572.     for_all_directions(dir) {
  1573.         if (border_at(x, y, dir, b) && borders_visible(dside, x, y, dir)) {
  1574.             bitmask |= 1 << dir;
  1575.         }
  1576.     }
  1577.     if (bitmask != 0) {
  1578.         xform(map, x, y, &sx, &sy);
  1579.         /* (should compute and pass in overlay) */
  1580.         draw_border_line_multiple(map->window, sx, sy, bitmask, map->vp->power, b, map->vp->angle);
  1581.     }
  1582. }
  1583.  
  1584. /* Draw all the connections of the given cell. */
  1585.  
  1586. static void
  1587. draw_connections(map, x, y, c)
  1588. Map *map;
  1589. int x, y, c;
  1590. {
  1591.     int xw = wrapx(x), dir, sx, sy, bitmask = 0;
  1592.     
  1593.     if (!terrain_visible(dside, xw, y) || !any_connections_at(x, y, c))
  1594.       return;
  1595.     for_all_directions(dir) {
  1596.         if (connection_at(x, y, dir, c)) {
  1597.             bitmask |= 1 << dir;
  1598.         }
  1599.     }
  1600.     if (bitmask != 0) {
  1601.         xform(map, x, y, &sx, &sy);
  1602.         /* (should compute and pass in overlay) */
  1603.         draw_connection_line_multiple(map->window, sx, sy, bitmask, map->vp->power, c, map->vp->angle);
  1604.     }
  1605. }
  1606.  
  1607. /* Draw all the units visible in the given cell. */
  1608. /* (x is not wrapped) */
  1609.  
  1610. static void
  1611. draw_units(map, x, y)
  1612. Map *map;
  1613. int x, y;
  1614. {
  1615.     int xw = wrapx(x), sx, sy, sw, sh, uview, u, s;
  1616.     Unit *unit;
  1617.     Rect tmprect;
  1618.     extern PicHandle dotdotdotpicture;
  1619.  
  1620.     if (units_visible(dside, xw, y)) {
  1621.         unit = unit_at(xw, y);
  1622.         if (unit != NULL) {
  1623.             xform(map, x, y, &sx, &sy);
  1624.             if (map->vp->uw <= 16) {
  1625.                 /* Adjust to unit part of cell. */
  1626.                 sw = map->vp->uw;  sh = map->vp->uh;
  1627.                 sx += (map->vp->hw - sw) / 2;  sy += (map->vp->hh - sw) / 2;
  1628.                 if (unit->occupant != NULL
  1629.                     && sw >= 8
  1630.                     && (unit->side == dside || all_see_all || u_see_occupants(unit->type))) {
  1631.                     /* Draw a "grouping box", in white, but with no occs drawn. */
  1632.                     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  1633.                     FillRect(&tmprect, QDPat(white));
  1634.                     FrameRect(&tmprect);
  1635.                 }
  1636.                 draw_unit_image(map->window, sx, sy, sw, sh,
  1637.                                 unit->type, side_number(unit->side), !completed(unit));
  1638.                 /* Indicate if more than one stacked here. */
  1639.                 if (unit->nexthere != NULL && sw > 8) {
  1640.                     SetRect(&tmprect, sx + sw/2 - 6, sy + sh - 2,
  1641.                                       sx + sw/2 + 6, sy + sh + 2);
  1642.                     /* (should clip to fit in cell) */
  1643.                     /* (should do a copybits) */
  1644.                     DrawPicture(dotdotdotpicture, &tmprect);
  1645.                 }
  1646.                 if (map->drawnames)
  1647.                   draw_unit_name(unit, sx, sy, sw, sh);
  1648.             } else {
  1649.                 for_all_stack(xw, y, unit) {
  1650.                     if (1 /* doesnt work right? - side_sees_unit(dside, unit) */) {
  1651.                         m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
  1652.                         draw_unit_and_occs(map, unit, sx, sy, sw, sh);
  1653.                     }
  1654.                 }
  1655.             }
  1656.         }
  1657.     } else {
  1658.         uview = unit_view(dside, xw, y);
  1659.         if (uview != EMPTY) {
  1660.             u = vtype(uview);  s = vside(uview);
  1661.             xform(map, x, y, &sx, &sy);
  1662.             /* Adjust to unit part of cell. */
  1663.             sx += (map->vp->hw - map->vp->uw) / 2;  sy += (map->vp->hh - map->vp->uh) / 2;
  1664.             draw_unit_image(map->window, sx, sy, map->vp->uw, map->vp->uh, u, s, 0);
  1665.         }
  1666.     }
  1667. }
  1668.  
  1669. static void
  1670. draw_unit_and_occs(map, unit, sx, sy, sw, sh)
  1671. Map *map;
  1672. Unit *unit;
  1673. int sx, sy, sw, sh;
  1674. {
  1675.     int u = unit->type, s = side_number(unit->side), sx2, sy2, sw2, sh2;
  1676.     Unit *occ;
  1677.     Rect tmprect;
  1678.  
  1679.     /* If an occupant's side is the same as its transport's, then there's
  1680.        really no need to draw its side emblem, since the transport's emblem
  1681.        will also be visible. */
  1682.     if (unit->transport && unit->side == unit->transport->side)
  1683.       s = -1;
  1684.     if (unit->occupant == NULL
  1685.         || sw <= 8
  1686.         || (unit->side != dside && !all_see_all && !u_see_occupants(unit->type))) {
  1687.         draw_unit_image(map->window, sx, sy, sw, sh, u, s, !completed(unit));
  1688.         if (map->drawnames)
  1689.           draw_unit_name(unit, sx, sy, sw, sh); 
  1690.     } else {
  1691.         /* Draw a sort of "grouping box", in white. */
  1692.         SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  1693.         FillRect(&tmprect, QDPat(white));
  1694.         FrameRect(&tmprect);
  1695.         /* Draw the transport in the UL quarter of the box. */
  1696.         m_xform_occupant(map, unit, unit, sx, sy, sw, sh, &sx2, &sy2, &sw2, &sh2);
  1697.         draw_unit_image(map->window, sx2, sy2, sw2, sh2, u, s, !completed(unit));
  1698.         if (map->drawnames)
  1699.           draw_unit_name(unit, sx2, sy2, sw2, sh2);
  1700.         /* Draw all the occupants, in the bottom half of the box. */
  1701.         for_all_occupants(unit, occ) {
  1702.             m_xform_occupant(map, unit, occ, sx, sy, sw, sh, &sx2, &sy2, &sw2, &sh2);
  1703.             draw_unit_and_occs(map, occ, sx2, sy2, sw2, sh2);
  1704.         }
  1705.     }
  1706. }
  1707.  
  1708. /* Indicate what kind of people are living in the given row. */
  1709.  
  1710. /* (should optimize by sharing border drawing for max efficiency) */
  1711.  
  1712. static void
  1713. draw_people_row(map, x0, y, len)
  1714. Map *map;
  1715. int x0, y, len;
  1716. {
  1717.     int pop, xx, x, sx, sy, sw, sh, ex, ey, ew, eh, dir, x1, y1, pop1;
  1718.     int bitmask1, bitmask2, drawemblemhere;
  1719.  
  1720.     for (xx = x0; xx < x0 + len; ++xx) {
  1721.         x = wrapx(xx);
  1722.         if (!terrain_visible(dside, x, y))
  1723.           continue;
  1724.         pop = people_side_at(x, y);
  1725.         bitmask1 = bitmask2 = 0;
  1726.         drawemblemhere = FALSE;
  1727.         /* Decide which edges are borders of the country. */
  1728.         for_all_directions(dir) {
  1729.             /* Don't do anything about edge cells. */
  1730.             if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1731.                 if (terrain_visible(dside, x1, y1)) {
  1732.                     pop1 = people_side_at(x1, y1);
  1733.                     if (pop != pop1) {
  1734.                         /* Borders with uninhabitated regions are drawn differently. */
  1735.                         if (pop == NOBODY || pop1 == NOBODY) {
  1736.                             bitmask2 |= 1 << dir;
  1737.                         } else {
  1738.                             bitmask1 |= 1 << dir;
  1739.                         }
  1740.                     }
  1741.                 } else {
  1742.                     /* Draw just people in the cells right at the edge of the known world. */
  1743.                     drawemblemhere = TRUE;
  1744.                 }
  1745.             }
  1746.         }
  1747.         /* Now draw both the edges and an emblem for the cell. */
  1748.         if ((bitmask1 | bitmask2) != 0 || (map->drawpeople && drawemblemhere)) {
  1749.             xform(map, x, y, &sx, &sy);
  1750.             if (bitmask1 != 0) {
  1751.                 draw_country_borders(map->window, sx, sy, bitmask1, map->vp->power, 0, map->vp->angle);
  1752.             }
  1753.             if (bitmask2 != 0) {
  1754.                 draw_country_borders(map->window, sx, sy, bitmask2, map->vp->power, 2, map->vp->angle);
  1755.             }
  1756.             /* Draw an emblem for the people in the cell. */
  1757.             if (map->drawpeople && pop != NOBODY) {
  1758.                 sw = map->vp->uw;  sh = map->vp->uh;
  1759.                 ew = min(sw, max(8, sw / 2));  eh = min(sh, max(8, sh / 2));
  1760.                 ex = sx + (map->vp->hw - map->vp->uw) / 2 + sw / 2 - ew / 2;  ey = sy + (map->vp->hh - map->vp->uh) / 2 + sh / 2 - eh / 2;
  1761.                 draw_side_emblem(map->window, ex, ey, ew, eh, pop, plain_emblem);
  1762.             }
  1763.         }
  1764.     }
  1765. }
  1766.  
  1767. /* This draws a small set of bar charts, one for each material type. */
  1768.  
  1769. static void
  1770. draw_materials(map, x, y)
  1771. Map *map;
  1772. int x, y;
  1773. {
  1774.     int m, t, sx, sy, mx, my, mw, mh, amt, maxamt, h;
  1775.     Rect graphrect;
  1776.     
  1777.     if (nummtypes == 0)
  1778.       return;
  1779.     mw = map->vp->uw / nummtypes /* should be count of displayable materials... */;  mh = map->vp->uh;
  1780.     if (mw <= 2 || mh <= 2)
  1781.       return;
  1782.     t = cell_terrain(x, y, map->vp->power);
  1783.     xform(map, x, y, &sx, &sy);
  1784.     mx = sx + (map->vp->hw - map->vp->uw) / 2;  my = sy + (map->vp->hh - map->vp->uh) / 2;
  1785.     for_all_material_types(m) {
  1786.         if (map->drawmaterials[m] && (maxamt = tm_storage_x(t, m)) > 0) {
  1787.             SetRect(&graphrect, mx + m * mw, my, mx + (m + 1) * mw, my + map->vp->uh);
  1788.             FrameRect(&graphrect);
  1789.             amt = material_at(x, y, m);
  1790.             h = (amt * mh) / maxamt;
  1791.             graphrect.top -= (mh - h);
  1792.             FillRect(&graphrect, QDPat(black));
  1793.         }
  1794.     }
  1795. }
  1796.  
  1797. static void
  1798. draw_ai_region(map, x, y)
  1799. Map *map;
  1800. int x, y;
  1801. {
  1802.     int thid, sx, sy, dir, x1, y1, thid1, bitmask = 0;
  1803.  
  1804.     thid = ai_region_at(dside, wrapx(x), y);
  1805.     /* Decide which edges are borders of the theater. */
  1806.     for_all_directions(dir) {
  1807.         /* Don't do anything about edge cells. */
  1808.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1809.             thid1 = ai_region_at(dside, x1, y1);
  1810.             if (thid != thid1) {
  1811.                 bitmask |= 1 << dir;
  1812.             }
  1813.         }
  1814.     }
  1815.     if (bitmask != 0) {
  1816.         xform(map, x, y, &sx, &sy);
  1817.         if (bitmask != 0) {
  1818.             draw_ai_region_borders(map->window, sx, sy, bitmask, map->vp->power);
  1819.         }
  1820.     }
  1821. }
  1822.  
  1823. /* Draw any text that should be associated with this cell. */
  1824.  
  1825. /* (could precompute what the string will lap over and move or truncate str),
  1826.    should be deterministic for each mag, so redraw doesn't scramble */
  1827.  
  1828. void
  1829. draw_legend(map, x, y)
  1830. Map *map;
  1831. int x, y;
  1832. {
  1833.     int xw, sx, sy;
  1834.     char *str, buf[BUFSIZE];
  1835.     Feature *feature;
  1836.  
  1837.     xw = wrapx(x);
  1838.     /* Draw the name of a terrain feature. */
  1839.     /* (should limit to one cell of feature, preferably centering on quasi-centroid) */    
  1840.     if (terrain_visible(dside, x, y)) {
  1841.         feature = feature_at(x, y);
  1842.         if (feature != NULL) {
  1843.             if (feature->size > 0) {
  1844.                 if ((feature->x == x && feature->y == y)
  1845.                     || (feature->x == 0 && feature->y == 0)
  1846.                     || 0 /* center far away */) {
  1847.                     str = feature_desc(feature, buf);
  1848.                     if (str != NULL) {
  1849.                         xform(map, x, y, &sx, &sy);
  1850.                         draw_legend_text(sx + map->vp->hw/2, sy + map->vp->hh/2, map->vp->uh, str, 0);
  1851.                     }
  1852.                 }
  1853.             }
  1854.         }
  1855.     }
  1856. }
  1857.  
  1858. void
  1859. draw_unit_blast(Map *map, Unit *unit, int blast)
  1860. {
  1861.     int sx, sy, sw, sh;
  1862.     RgnHandle tmprgn;
  1863.  
  1864.     tmprgn = NewRgn();
  1865.     GetClip(tmprgn);
  1866.     /* Clip to the content area of the map's window. */
  1867.     ClipRect(&(map->contentrect));
  1868.     SHIFT_ORIGIN(map);
  1869.     m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
  1870.     draw_blast_image(map->window, sx, sy, sw, sh, blast);
  1871.     RESET_ORIGIN(map);
  1872.     SetClip(tmprgn);
  1873.     DisposeRgn(tmprgn);
  1874. }
  1875.  
  1876. void
  1877. clear_unit_blast(Map *map, Unit *unit, int blast)
  1878. {
  1879.     int sx, sy, sw, sh;
  1880.     RgnHandle tmprgn;
  1881.  
  1882.     tmprgn = NewRgn();
  1883.     GetClip(tmprgn);
  1884.     /* Clip to the content area of the map's window. */
  1885.     ClipRect(&(map->contentrect));
  1886.     SHIFT_ORIGIN(map);
  1887.     m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
  1888.     clear_blast_image(map->window, sx, sy, sw, sh, blast);
  1889.     RESET_ORIGIN(map);
  1890.     SetClip(tmprgn);
  1891.     DisposeRgn(tmprgn);
  1892. }
  1893.  
  1894. /* Draw all the selections of all the units. */
  1895.  
  1896. void
  1897. draw_selections(Map *map)
  1898. {
  1899.     int i;
  1900.     GrafPtr oldport;
  1901.     RgnHandle tmprgn;
  1902.     Unit *unit;
  1903.  
  1904.      GetPort(&oldport);
  1905.     SetPort(map->window);
  1906.     tmprgn = NewRgn();
  1907.     GetClip(tmprgn);
  1908.     ClipRect(&(map->contentrect));
  1909.     SHIFT_ORIGIN(map);
  1910.     for (i = 0; i < map->numselections; ++i) {
  1911.         unit = map->selections[i];
  1912.         draw_selected_unit(map, unit);
  1913.     }
  1914.     RESET_ORIGIN(map);
  1915.     SetClip(tmprgn);
  1916.     DisposeRgn(tmprgn);
  1917.     if (map->numselections > 0) {
  1918.         unit = map->selections[0];
  1919.         if (in_play(unit)) {
  1920.             draw_unit_info(map);
  1921.         }
  1922.     }
  1923.     SetPort(oldport);
  1924. }
  1925.  
  1926. /* Draw all the selected units in the given cell. */
  1927.  
  1928. void
  1929. draw_selections_at(map, x, y)
  1930. Map *map;
  1931. int x, y;
  1932. {
  1933.     int i;
  1934.     GrafPtr oldport;
  1935.     RgnHandle tmprgn;
  1936.     Unit *unit;
  1937.  
  1938.      GetPort(&oldport);
  1939.     SetPort(map->window);
  1940.     tmprgn = NewRgn();
  1941.     GetClip(tmprgn);
  1942.     ClipRect(&(map->contentrect));
  1943.     SHIFT_ORIGIN(map);
  1944.     for (i = 0; i < map->numselections; ++i) {
  1945.         unit = map->selections[i];
  1946.         if (unit && unit->x == x && unit->y == y) {
  1947.             draw_selected_unit(map, unit);
  1948.         }
  1949.     }
  1950.     RESET_ORIGIN(map);
  1951.     SetClip(tmprgn);
  1952.     DisposeRgn(tmprgn);
  1953.     if (map->numselections > 0) {
  1954.         unit = map->selections[0];
  1955.         if (in_play(unit) && unit->x == x && unit->y == y) {
  1956.             draw_unit_info(map);
  1957.         }
  1958.     }
  1959.     SetPort(oldport);
  1960. }
  1961.  
  1962. void
  1963. draw_selected_unit_setport(map, unit)
  1964. Map *map;
  1965. Unit *unit;
  1966. {
  1967.     GrafPtr oldport;
  1968.     RgnHandle tmprgn;
  1969.  
  1970.      GetPort(&oldport);
  1971.     SetPort(map->window);
  1972.     tmprgn = NewRgn();
  1973.     GetClip(tmprgn);
  1974.     ClipRect(&(map->contentrect));
  1975.     SHIFT_ORIGIN(map);
  1976.     draw_selected_unit(map, unit);
  1977.     RESET_ORIGIN(map);
  1978.     SetClip(tmprgn);
  1979.     DisposeRgn(tmprgn);
  1980.     if (map->numselections > 0) {
  1981.         unit = map->selections[0];
  1982.         if (in_play(unit)) {
  1983.             draw_unit_info(map);
  1984.         }
  1985.     }
  1986.     SetPort(oldport);
  1987. }
  1988.  
  1989. /* Draw a single selected unit on the given map.  Assumes that grafport already set. */
  1990.  
  1991. void
  1992. draw_selected_unit(map, unit)
  1993. Map *map;
  1994. Unit *unit;
  1995. {
  1996.     int sx, sy, sw, sh, size, wholecell = FALSE, drawmag = FALSE;
  1997.     int sx1, sy1, sw1, sh1;
  1998.     Rect tmprect;
  1999.  
  2000.     if (!in_play(unit))
  2001.       return; /* unselect it too? */
  2002.     if (map->vp->uw >= 32) {
  2003.         m_xform_unit_self(map, unit, &sx, &sy, &sw, &sh);
  2004.         if (map->numselections == 1
  2005.             && sw < 16
  2006.             && unit->transport != NULL) {
  2007.             wholecell = TRUE;
  2008.             drawmag = TRUE;
  2009.             sx1 = sx;  sy1 = sy;  sw1 = sw;  sh1 = sh;
  2010.         }
  2011.     } else {
  2012.         wholecell = TRUE;
  2013.     }
  2014.     if (wholecell) {
  2015.         xform(map, unit->x, unit->y, &sx, &sy);
  2016.         /* Adjust to unit part of cell. */
  2017.         sx += (map->vp->hw - map->vp->uw) / 2;  sy += (map->vp->hh - map->vp->uh) / 2;
  2018.         sw = map->vp->uw;  sh = map->vp->uh;
  2019.     }
  2020.     if (0 /* not actually within visible area */)
  2021.       return;
  2022.     /* Indicate a unit's plans/tasks in some useful fashion. */
  2023.     if (map->drawplans
  2024.         && unit->plan
  2025.         && unit->plan->tasks) {
  2026.         int sx2, sy2;
  2027.         Task *task = unit->plan->tasks, *nexttask;
  2028.  
  2029.         if (task != NULL) {
  2030.             if ((nexttask = task->next) != NULL) {
  2031.                 switch (nexttask->type) {
  2032.                     case TASK_MOVE_TO:
  2033.                     case TASK_HIT_UNIT:
  2034.                         if (in_area(nexttask->args[0], nexttask->args[1])) {
  2035.                             xform(map, nexttask->args[0], nexttask->args[1], &sx2, &sy2);
  2036.                             PenPat(QDPat(ltGray));
  2037.                             MoveTo(sx + sw/2, sy + sh/2);
  2038.                             LineTo(sx2 + map->vp->hw/2, sy2 + map->vp->hh/2);
  2039.                             PenNormal();
  2040.                         }
  2041.                         /* else warn unobtrusively? tasks should not go outside world,
  2042.                            but not a fatal problem if they do... */
  2043.                 }
  2044.             }
  2045.             switch (task->type) {
  2046.                 case TASK_MOVE_TO:
  2047.                 case TASK_HIT_UNIT:
  2048.                     if (in_area(task->args[0], task->args[1])) {
  2049.                         xform(map, task->args[0], task->args[1], &sx2, &sy2);
  2050.                         PenPat(QDPat(dkGray));
  2051.                         MoveTo(sx + sw/2, sy + sh/2);
  2052.                         LineTo(sx2 + map->vp->hw/2, sy2 + map->vp->hh/2);
  2053.                         PenNormal();
  2054.                     }
  2055.             }
  2056.         }
  2057.     }
  2058.     /* Draw magnification lines pointing to the true location of the unit. */
  2059.     if (drawmag) {
  2060.         /* PenPat should already be black. */
  2061.         MoveTo(sx,      sy);       LineTo(sx1,       sy1);
  2062.         MoveTo(sx + sw, sy);       LineTo(sx1 + sw1, sy1);
  2063.         MoveTo(sx,      sy + sh);  LineTo(sx1,       sy1 + sh1);
  2064.         MoveTo(sx + sw, sy + sh);  LineTo(sx1 + sw1, sy1 + sh1);
  2065.     }
  2066.     /* Be sure the selected unit is drawn. */
  2067.     draw_unit_image(map->window, sx, sy, sw, sh,
  2068.                     unit->type, side_number(unit->side), !completed(unit));
  2069.     /* Draw a highlighting rectangle. */
  2070.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  2071.     /* A hack to prevent leakage into the grid. */
  2072.     if (map->drawgrid && map->vp->power == 5) --tmprect.bottom;
  2073.     /* First, draw an outer frame, for contrast. */
  2074.     if (map->autoselect && unit->act && unit->act->initacp > 0 && unit->act->acp > 0) {
  2075.         PenPat(&animation_patterns[animation_pattern_state]);
  2076.     } else {
  2077.         PenPat(QDPat(white));
  2078.     }
  2079.     FrameRect(&tmprect);
  2080.     InsetRect(&tmprect, 1, 1);
  2081.     /* Black is for units that can still act, dark gray for actors, gray if the
  2082.        unit can't do anything. */
  2083.     PenPat((unit->act && unit->act->initacp > 0) ?
  2084.             ((unit->act->acp > 0) ? QDPat(black) : QDPat(dkGray)) : QDPat(gray));
  2085.     /* Wide border if awake, narrow if asleep or napping. */
  2086.     size = ((unit->plan && (unit->plan->asleep || unit->plan->reserve)) ? 1 : 2);
  2087.     PenSize(size, size);
  2088.     FrameRect(&tmprect);
  2089.     PenNormal();
  2090.     DGprintf("draw selection of %s at %d,%d\n", unit_desig(unit));
  2091. }
  2092.  
  2093. void
  2094. draw_selection_animation(map, unit)
  2095. Map *map;
  2096. Unit *unit;
  2097. {
  2098.     int sx, sy, sw, sh, wholecell = FALSE, drawmag = FALSE;
  2099.     int sx1, sy1, sw1, sh1;
  2100.     Rect tmprect;
  2101.     GrafPtr oldport;
  2102.     RgnHandle tmprgn;
  2103.  
  2104.     if (!in_play(unit))
  2105.       return; /* unselect it too? */
  2106.      GetPort(&oldport);
  2107.     SetPort(map->window);
  2108.     tmprgn = NewRgn();
  2109.     GetClip(tmprgn);
  2110.     ClipRect(&(map->contentrect));
  2111.     SHIFT_ORIGIN(map);
  2112.     if (map->vp->uw >= 32) {
  2113.         m_xform_unit_self(map, unit, &sx, &sy, &sw, &sh);
  2114.         if (map->numselections == 1
  2115.             && sw < 16
  2116.             && unit->transport != NULL) {
  2117.             wholecell = TRUE;
  2118.             drawmag = TRUE;
  2119.             sx1 = sx;  sy1 = sy;  sw1 = sw;  sh1 = sh;
  2120.         }
  2121.     } else {
  2122.         wholecell = TRUE;
  2123.     }
  2124.     if (wholecell) {
  2125.         xform(map, unit->x, unit->y, &sx, &sy);
  2126.         /* Adjust to unit part of cell. */
  2127.         sx += (map->vp->hw - map->vp->uw) / 2;  sy += (map->vp->hh - map->vp->uh) / 2;
  2128.         sw = map->vp->uw;  sh = map->vp->uh;
  2129.     }
  2130.     /* Draw a highlighting rectangle. */
  2131.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  2132.     /* A hack to prevent leakage into the grid. */
  2133.     if (map->drawgrid && map->vp->power == 5) --tmprect.bottom;
  2134.     /* First, draw an outer white frame, for contrast. */
  2135.     if (unit->act && unit->act->initacp > 0 && unit->act->acp > 0) {
  2136.         PenPat(&animation_patterns[animation_pattern_state]);
  2137.     } else {
  2138.         PenPat(QDPat(white));
  2139.     }
  2140.     FrameRect(&tmprect);
  2141.     PenPat(QDPat(black));
  2142.     RESET_ORIGIN(map);
  2143.     SetClip(tmprgn);
  2144.     DisposeRgn(tmprgn);
  2145.     SetPort(oldport);
  2146. }
  2147.  
  2148. /* (should only redraw any given cell once) */
  2149.  
  2150. void
  2151. erase_selections(map)
  2152. Map *map;
  2153. {
  2154.     int i;
  2155.     GrafPtr oldport;
  2156.     RgnHandle tmprgn;
  2157.     Unit *unit;
  2158.  
  2159.      GetPort(&oldport);
  2160.     SetPort(map->window);
  2161.     tmprgn = NewRgn();
  2162.     GetClip(tmprgn);
  2163.     ClipRect(&(map->contentrect));
  2164.     SHIFT_ORIGIN(map);
  2165.     for (i = 0; i < map->numselections; ++i) {
  2166.         unit = map->selections[i];
  2167.         draw_unselected_unit(map, unit);
  2168.     }
  2169.     RESET_ORIGIN(map);
  2170.     SetClip(tmprgn);
  2171.     DisposeRgn(tmprgn);
  2172.     SetPort(oldport);
  2173. }
  2174.  
  2175. void
  2176. erase_selection(map, unit)
  2177. Map *map;
  2178. Unit *unit;
  2179. {
  2180.     GrafPtr oldport;
  2181.     RgnHandle tmprgn;
  2182.  
  2183.      GetPort(&oldport);
  2184.     SetPort(map->window);
  2185.     tmprgn = NewRgn();
  2186.     GetClip(tmprgn);
  2187.     ClipRect(&(map->contentrect));
  2188.     SHIFT_ORIGIN(map);
  2189.     draw_unselected_unit(map, unit);
  2190.     RESET_ORIGIN(map);
  2191.     SetClip(tmprgn);
  2192.     DisposeRgn(tmprgn);
  2193.     SetPort(oldport);
  2194. }
  2195.  
  2196. void
  2197. draw_unselected_unit(map, unit)
  2198. Map *map;
  2199. Unit *unit;
  2200. {
  2201.     if (!in_play(unit))
  2202.       return;
  2203.     draw_row(map, unit->x, unit->y, 1, TRUE);
  2204.     DGprintf("erase selection of %s at %d,%d\n", unit_desig(unit));
  2205. }
  2206.  
  2207. void
  2208. force_map_update(map)
  2209. Map *map;
  2210. {
  2211.     force_update(map->window);
  2212. }
  2213.  
  2214. /* Remove and destroy the map object. */
  2215.  
  2216. void
  2217. destroy_map(map)
  2218. Map *map;
  2219. {
  2220.     Map *map2;
  2221.     
  2222.     if (maplist == map) {
  2223.         maplist = map->next;
  2224.     } else {
  2225.         for_all_maps(map2) {
  2226.             if (map2->next == map) {
  2227.                 map2->next = map->next;
  2228.             }
  2229.         }
  2230.     }
  2231.     /* (should destroy substructs) */
  2232.     free(map);
  2233. }
  2234.  
  2235. void
  2236. activate_map(map, activate)
  2237. Map *map;
  2238. int activate;
  2239. {
  2240.     Rect growRect;
  2241.  
  2242.     if (activate) {
  2243.         HiliteControl(map->vscrollbar, 0);
  2244.         HiliteControl(map->hscrollbar, 0);
  2245.         /* Controls need to be redrawn on activation. */
  2246.         (*(map->vscrollbar))->contrlVis = 255;
  2247.         (*(map->hscrollbar))->contrlVis = 255;
  2248.         InvalRect(&(*(map->vscrollbar))->contrlRect);
  2249.         InvalRect(&(*(map->hscrollbar))->contrlRect);
  2250.         /* The growbox needs to be redrawn on activation. */
  2251.         growRect = map->window->portRect;
  2252.         /* adjust for the scrollbars */
  2253.         growRect.top = growRect.bottom - sbarwid;
  2254.         growRect.left = growRect.right - sbarwid;
  2255.         InvalRect(&growRect);
  2256.     } else {
  2257.         /* The scrollbars must be deactivated. */
  2258.         HiliteControl(map->vscrollbar, 255);
  2259.         HiliteControl(map->hscrollbar, 255);
  2260. #if 0  /* We don't want to hide them though, because the window bg is not white. */
  2261.         HideControl(map->vscrollbar);
  2262.         HideControl(map->hscrollbar);
  2263. #endif
  2264.         /* The growbox should be changed immediately on deactivation. */
  2265.         DrawGrowIcon(map->window);
  2266.     }
  2267. }
  2268.  
  2269. void
  2270. print_map(map)
  2271. Map *map;
  2272. {
  2273. /*    TPPrPort printport;
  2274.     extern THPrint printrecordhandle;
  2275.  
  2276.     printport = PrOpenDoc(printrecordhandle, nil, nil);
  2277.     PrCloseDoc(printport); */
  2278. }
  2279.  
  2280. /* (should be able to mention borders and conns also - share code with curses?) */
  2281. /* (could be a generic routine) */
  2282. void
  2283. oneliner(map, sx, sy)
  2284. Map *map;
  2285. int sx, sy;
  2286. {
  2287.     int x, y, t2, uview, u, s, ps = NOBODY, dep, sayin = FALSE;
  2288.     char *peopdesc = NULL, *sidedesc;
  2289.     char descbuf[80];
  2290.     Unit *unit;
  2291.     Side *side;
  2292.     char *mplayer_at_desig();
  2293.  
  2294.     if (!m_nearest_cell(map, sx, sy, &x, &y)) {
  2295.         strcpy(tmpbuf, "(nothing)");
  2296.         return;
  2297.     } else if (terrain_visible(dside, x, y)) {
  2298.         strcpy(tmpbuf, " ");
  2299.         /* Describe the side of the people here. */
  2300.         if (people_sides_defined()) {
  2301.             ps = people_side_at(x, y);
  2302.             if (ps != NOBODY) {
  2303.                 side = side_n(ps);
  2304.                 if (side == NULL) {
  2305.                     peopdesc = "indep";
  2306.                 } else if (side == dside) {
  2307.                     peopdesc = "your";
  2308.                 } else {
  2309.                     peopdesc = side_adjective(side);
  2310.                     if (peopdesc[0] == '\0') {
  2311.                         sprintf(descbuf, "s%d", side->id);
  2312.                         peopdesc = descbuf;
  2313.                     }
  2314.                 }
  2315.             }
  2316.         }
  2317.         if (units_visible(dside, x, y)) {
  2318.             m_nearest_unit(map, sx, sy, &unit);
  2319.             if (unit != NULL) {
  2320.                 if (unit->side != dside) {
  2321.                     sidedesc = side_adjective(unit->side);
  2322.                     if (ps != NOBODY && ps == side_number(unit->side)) {
  2323.                         peopdesc = "own";
  2324.                     }
  2325.                 } else {
  2326.                     sidedesc = "your";
  2327.                 }
  2328.                 strcat(tmpbuf, sidedesc);
  2329.                 if (unit->name) {
  2330.                     strcat(tmpbuf, " ");
  2331.                     strcat(tmpbuf, u_type_name(unit->type));
  2332.                     strcat(tmpbuf, " ");
  2333.                     strcat(tmpbuf, unit->name);
  2334.                 } else if (unit->number > 0) {
  2335.                     tprintf(tmpbuf, " %d%s %s",
  2336.                             unit->number, ordinal_suffix(unit->number), u_type_name(unit->type));
  2337.                 } else {
  2338.                     strcat(tmpbuf, " ");
  2339.                     strcat(tmpbuf, u_type_name(unit->type));
  2340.                 }
  2341.                 if (Debug || DebugG || DebugM) {
  2342.                     tprintf(tmpbuf, " #%d", unit->id);
  2343.                 }
  2344.                 sayin = TRUE;
  2345.             }
  2346.         } else {
  2347.             if ((uview = unit_view(dside, x, y)) != EMPTY) {
  2348.                 u = vtype(uview);  s = vside(uview);
  2349.                 if (ps != NOBODY && ps == s) {
  2350.                     peopdesc = "own";
  2351.                 }
  2352.                 strcat(tmpbuf, side_adjective(side_n(s)));
  2353.                 strcat(tmpbuf, " ");
  2354.                 strcat(tmpbuf, u_type_name(u));
  2355.                 sayin = TRUE;
  2356.             }
  2357.         }
  2358.         if (sayin) {
  2359.             strcat(tmpbuf, " (in ");
  2360.         }
  2361.         if (peopdesc != NULL) {
  2362.             strcat(tmpbuf, peopdesc);
  2363.             strcat(tmpbuf, " ");
  2364.         }
  2365.         t2 = cell_terrain(x, y, 0);
  2366.         strcat(tmpbuf, t_type_name(t2));
  2367.         if (sayin) {
  2368.             strcat(tmpbuf, ")");
  2369.         }
  2370.         if (elevations_defined()) {
  2371.             tprintf(tmpbuf, " Elev %d", elev_at(x, y));
  2372.         }
  2373.         if (temperatures_defined()) {
  2374.             tprintf(tmpbuf, " T %d°", temperature_at(x, y));
  2375.         }
  2376.         if (numcoattypes > 0) {
  2377.             for_all_terrain_types(t2) {
  2378.                 if (t_is_coating(t2)
  2379.                     && aux_terrain_defined(t2)
  2380.                     && ((dep = aux_terrain_view(dside, x, y, t2)) > 0)) {
  2381.                     tprintf(tmpbuf, " %s %d", t_type_name(t2), dep);
  2382.                 }
  2383.             }
  2384.         }
  2385.     } else {
  2386.         sprintf(tmpbuf, "(unknown)");
  2387.     }
  2388.     tprintf(tmpbuf, " @%d,%d", x, y);
  2389.     if (terrain_visible(dside, x, y)) {
  2390.         Feature *feature;
  2391.         char *feature_desc();
  2392.         char *str, buf[BUFSIZE];
  2393.  
  2394.         feature = feature_at(x, y);
  2395.         if (feature != NULL) {
  2396.             if (feature->size > 0) {
  2397.                 str = feature_desc(feature, buf);
  2398.                 if (str != NULL) {
  2399.                     tprintf(tmpbuf, " (%s)", str);
  2400.                 }
  2401.             }
  2402.         }
  2403.     }
  2404.     if (map->drawai && side_has_ai(dside)) {
  2405.         strcat(tmpbuf, " ");
  2406.         strcat(tmpbuf, ai_at_desig(dside, x, y));
  2407.     }
  2408. }
  2409.